# HG changeset patch # User Thomas Wuerthinger # Date 1307516394 -7200 # Node ID d90bf514d647549650a802dcc42ce047550b9046 # Parent 810e2d253e007e9092da1e5a766060ddda815d06 Renamed packages. diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/C1XCompilation.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/C1XCompilation.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,310 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.max.graal.compiler; + +import java.util.*; + +import com.oracle.max.asm.*; +import com.oracle.max.graal.compiler.alloc.*; +import com.oracle.max.graal.compiler.asm.*; +import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.compiler.gen.*; +import com.oracle.max.graal.compiler.gen.LIRGenerator.*; +import com.oracle.max.graal.compiler.graph.*; +import com.oracle.max.graal.compiler.lir.*; +import com.oracle.max.graal.compiler.observer.*; +import com.oracle.max.graal.compiler.value.*; +import com.sun.cri.ci.*; +import com.sun.cri.ri.*; + +/** + * This class encapsulates global information about the compilation of a particular method, + * including a reference to the runtime, statistics about the compiled code, etc. + */ +public final class C1XCompilation { + + private static ThreadLocal currentCompilation = new ThreadLocal(); + + public final C1XCompiler compiler; + public final CiTarget target; + public final RiRuntime runtime; + public final RiMethod method; + public final RiRegisterConfig registerConfig; + public final CiStatistics stats; + public final CiAssumptions assumptions = new CiAssumptions(); + public final FrameState placeholderState; + + public CompilerGraph graph = new CompilerGraph(); + + private boolean hasExceptionHandlers; + private final C1XCompilation parent; + + /** + * @see #setNotTypesafe() + * @see #isTypesafe() + */ + private boolean typesafe = true; + + private int nextID = 1; + + private FrameMap frameMap; + private TargetMethodAssembler assembler; + + private IR hir; + + private LIRGenerator lirGenerator; + + /** + * Creates a new compilation for the specified method and runtime. + * + * @param compiler the compiler + * @param method the method to be compiled or {@code null} if generating code for a stub + * @param osrBCI the bytecode index for on-stack replacement, if requested + * @param stats externally supplied statistics object to be used if not {@code null} + */ + public C1XCompilation(C1XCompiler compiler, RiMethod method, int osrBCI, CiStatistics stats) { + if (osrBCI != -1) { + throw new CiBailout("No OSR supported"); + } + this.parent = currentCompilation.get(); + currentCompilation.set(this); + this.compiler = compiler; + this.target = compiler.target; + this.runtime = compiler.runtime; + this.method = method; + this.stats = stats == null ? new CiStatistics() : stats; + this.registerConfig = method == null ? compiler.globalStubRegisterConfig : runtime.getRegisterConfig(method); + this.placeholderState = method != null && method.minimalDebugInfo() ? new FrameState(method, 0, 0, 0, 0, graph) : null; + + if (compiler.isObserved()) { + compiler.fireCompilationStarted(new CompilationEvent(this)); + } + } + + public void close() { + currentCompilation.set(parent); + } + + public IR hir() { + return hir; + } + + /** + * Records that this compilation has exception handlers. + */ + public void setHasExceptionHandlers() { + hasExceptionHandlers = true; + } + + /** + * Translates a given kind to a canonical architecture kind. + * This is an identity function for all but {@link CiKind#Word} + * which is translated to {@link CiKind#Int} or {@link CiKind#Long} + * depending on whether or not this is a {@linkplain #is64Bit() 64-bit} + * compilation. + */ + public CiKind archKind(CiKind kind) { + if (kind.isWord()) { + return target.arch.is64bit() ? CiKind.Long : CiKind.Int; + } + return kind; + } + + /** + * Determines if two given kinds are equal at the {@linkplain #archKind(CiKind) architecture} level. + */ + public boolean archKindsEqual(CiKind kind1, CiKind kind2) { + return archKind(kind1) == archKind(kind2); + } + + /** + * Records an assumption that the specified type has no finalizable subclasses. + * + * @param receiverType the type that is assumed to have no finalizable subclasses + * @return {@code true} if the assumption was recorded and can be assumed; {@code false} otherwise + */ + public boolean recordNoFinalizableSubclassAssumption(RiType receiverType) { + return false; + } + + /** + * Converts this compilation to a string. + * + * @return a string representation of this compilation + */ + @Override + public String toString() { + return "compile: " + method; + } + + /** + * Builds the block map for the specified method. + * + * @param method the method for which to build the block map + * @param osrBCI the OSR bytecode index; {@code -1} if this is not an OSR + * @return the block map for the specified method + */ + public BlockMap getBlockMap(RiMethod method) { + BlockMap map = new BlockMap(method); + map.build(); + if (compiler.isObserved()) { + String label = CiUtil.format("BlockListBuilder %f %r %H.%n(%p)", method, true); + compiler.fireCompilationEvent(new CompilationEvent(this, label, map, method.code().length)); + } + stats.bytecodeCount += method.code().length; + return map; + } + + /** + * Returns the frame map of this compilation. + * @return the frame map + */ + public FrameMap frameMap() { + return frameMap; + } + + public TargetMethodAssembler assembler() { + if (assembler == null) { + AbstractAssembler asm = compiler.backend.newAssembler(registerConfig); + assembler = new TargetMethodAssembler(asm); + assembler.setFrameSize(frameMap.frameSize()); + assembler.targetMethod.setCustomStackAreaOffset(frameMap.offsetToCustomArea()); + } + return assembler; + } + + public boolean hasExceptionHandlers() { + return hasExceptionHandlers; + } + + public CiResult compile() { + CiTargetMethod targetMethod; + try { + emitHIR(); + emitLIR(); + targetMethod = emitCode(); + + if (C1XOptions.PrintMetrics) { + C1XMetrics.BytecodesCompiled += method.code().length; + } + } catch (CiBailout b) { + return new CiResult(null, b, stats); + } catch (Throwable t) { + if (C1XOptions.BailoutOnException) { + return new CiResult(null, new CiBailout("Exception while compiling: " + method, t), stats); + } else { + throw new RuntimeException(t); + } + } finally { + if (compiler.isObserved()) { + compiler.fireCompilationFinished(new CompilationEvent(this)); + } + } + + return new CiResult(targetMethod, null, stats); + } + + public IR emitHIR() { + hir = new IR(this); + hir.build(); + return hir; + } + + public void initFrameMap(int numberOfLocks) { + frameMap = this.compiler.backend.newFrameMap(method, numberOfLocks); + } + + private void emitLIR() { + if (C1XOptions.GenLIR) { + if (C1XOptions.PrintTimers) { + C1XTimers.LIR_CREATE.start(); + } + + initFrameMap(hir.maxLocks()); + + lirGenerator = compiler.backend.newLIRGenerator(this); + + for (LIRBlock begin : hir.linearScanOrder()) { + lirGenerator.doBlock(begin); + } + + if (C1XOptions.PrintTimers) { + C1XTimers.LIR_CREATE.stop(); + } + + if (C1XOptions.PrintLIR && !TTY.isSuppressed()) { + LIRList.printLIR(hir.linearScanOrder()); + } + + new LinearScan(this, hir, lirGenerator, frameMap()).allocate(); + } + } + + private CiTargetMethod emitCode() { + if (C1XOptions.GenLIR && C1XOptions.GenCode) { + final LIRAssembler lirAssembler = compiler.backend.newLIRAssembler(this); + lirAssembler.emitCode(hir.linearScanOrder()); + + // generate code for slow cases + lirAssembler.emitLocalStubs(); + + // generate deoptimization stubs + ArrayList deoptimizationStubs = lirGenerator.deoptimizationStubs(); + if (deoptimizationStubs != null) { + for (DeoptimizationStub stub : deoptimizationStubs) { + lirAssembler.emitDeoptizationStub(stub); + } + } + + // generate traps at the end of the method + lirAssembler.emitTraps(); + + CiTargetMethod targetMethod = assembler().finishTargetMethod(method, runtime, lirAssembler.registerRestoreEpilogueOffset, false); + if (assumptions.count() > 0) { + targetMethod.setAssumptions(assumptions); + } + + if (compiler.isObserved()) { + compiler.fireCompilationEvent(new CompilationEvent(this, "After code generation", graph, false, true, targetMethod)); + } + + if (C1XOptions.PrintTimers) { + C1XTimers.CODE_CREATE.stop(); + } + return targetMethod; + } + + return null; + } + + public int nextID() { + return nextID++; + } + + public static C1XCompilation compilation() { + C1XCompilation compilation = currentCompilation.get(); + assert compilation != null; + return compilation; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/C1XCompiler.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/C1XCompiler.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler; + +import java.util.*; + +import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.compiler.globalstub.*; +import com.oracle.max.graal.compiler.observer.*; +import com.oracle.max.graal.compiler.target.*; +import com.sun.cri.ci.*; +import com.sun.cri.ri.*; +import com.sun.cri.xir.*; + +/** + * This class implements the compiler interface for C1X. + * + * @author Thomas Wuerthinger + * @author Ben L. Titzer + */ +public class C1XCompiler extends ObservableCompiler { + + public final Map stubs = new HashMap(); + + /** + * The target that this compiler has been configured for. + */ + public final CiTarget target; + + /** + * The runtime that this compiler has been configured for. + */ + public final RiRuntime runtime; + + /** + * The XIR generator that lowers Java operations to machine operations. + */ + public final RiXirGenerator xir; + + /** + * The backend that this compiler has been configured for. + */ + public final Backend backend; + + public final RiRegisterConfig globalStubRegisterConfig; + + public C1XCompiler(RiRuntime runtime, CiTarget target, RiXirGenerator xirGen, RiRegisterConfig globalStubRegisterConfig) { + this.runtime = runtime; + this.target = target; + this.xir = xirGen; + this.globalStubRegisterConfig = globalStubRegisterConfig; + this.backend = Backend.create(target.arch, this); + init(); + } + + public CiResult compileMethod(RiMethod method, int osrBCI, RiXirGenerator xirGenerator, CiStatistics stats) { + long startTime = 0; + int index = C1XMetrics.CompiledMethods++; + if (C1XOptions.PrintCompilation) { + TTY.print(String.format("C1X %4d %-70s %-45s | ", index, method.holder().name(), method.name())); + startTime = System.nanoTime(); + } + + CiResult result = null; + TTY.Filter filter = new TTY.Filter(C1XOptions.PrintFilter, method); + C1XCompilation compilation = new C1XCompilation(this, method, osrBCI, stats); + try { + result = compilation.compile(); + } finally { + filter.remove(); + compilation.close(); + if (C1XOptions.PrintCompilation && !TTY.isSuppressed()) { + long time = (System.nanoTime() - startTime) / 100000; + TTY.println(String.format("%3d.%dms", time / 10, time % 10)); + } + } + + return result; + } + + private void init() { + final List xirTemplateStubs = xir.buildTemplates(backend.newXirAssembler()); + final GlobalStubEmitter emitter = backend.newGlobalStubEmitter(); + + if (xirTemplateStubs != null) { + for (XirTemplate template : xirTemplateStubs) { + TTY.Filter filter = new TTY.Filter(C1XOptions.PrintFilter, template.name); + try { + stubs.put(template, emitter.emit(template, runtime)); + } finally { + filter.remove(); + } + } + } + + for (GlobalStub.Id id : GlobalStub.Id.values()) { + TTY.Filter suppressor = new TTY.Filter(C1XOptions.PrintFilter, id); + try { + stubs.put(id, emitter.emit(id, runtime)); + } finally { + suppressor.remove(); + } + } + + if (C1XOptions.PrintCFGToFile) { + addCompilationObserver(new CFGPrinterObserver()); + } + if (C1XOptions.PrintDOTGraphToFile) { + addCompilationObserver(new GraphvizPrinterObserver(false)); + } + if (C1XOptions.PrintDOTGraphToPdf) { + addCompilationObserver(new GraphvizPrinterObserver(true)); + } + if (C1XOptions.PrintIdealGraphLevel != 0) { + CompilationObserver observer; + if (C1XOptions.PrintIdealGraphFile) { + observer = new IdealGraphPrinterObserver(); + } else { + observer = new IdealGraphPrinterObserver(C1XOptions.PrintIdealGraphAddress, C1XOptions.PrintIdealGraphPort); + } + addCompilationObserver(observer); + } + } + + public GlobalStub lookupGlobalStub(GlobalStub.Id id) { + GlobalStub globalStub = stubs.get(id); + assert globalStub != null : "no stub for global stub id: " + id; + return globalStub; + } + + public GlobalStub lookupGlobalStub(XirTemplate template) { + GlobalStub globalStub = stubs.get(template); + assert globalStub != null : "no stub for XirTemplate: " + template; + return globalStub; + } + + public GlobalStub lookupGlobalStub(CiRuntimeCall runtimeCall) { + GlobalStub globalStub = stubs.get(runtimeCall); + if (globalStub == null) { + globalStub = backend.newGlobalStubEmitter().emit(runtimeCall, runtime); + stubs.put(runtimeCall, globalStub); + } + + assert globalStub != null : "could not find global stub for runtime call: " + runtimeCall; + return globalStub; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/C1XMetrics.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/C1XMetrics.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler; + +import java.lang.reflect.*; +import java.util.*; + +import com.oracle.max.graal.compiler.debug.*; + + +/** + * This class contains a number of fields that collect metrics about compilation, particularly + * the number of times certain optimizations are performed. + */ +public class C1XMetrics { + public static int CompiledMethods; + public static int TargetMethods; + public static int LocalValueNumberHits; + public static int ValueMapResizes; + public static int InlinedFinalizerChecks; + public static int InlineForcedMethods; + public static int InlineForbiddenMethods; + public static int InlinedJsrs; + public static int BlocksDeleted; + public static int BytecodesCompiled; + public static int CodeBytesEmitted; + public static int SafepointsEmitted; + public static int ExceptionHandlersEmitted; + public static int DataPatches; + public static int DirectCallSitesEmitted; + public static int IndirectCallSitesEmitted; + public static int HIRInstructions; + public static int LiveHIRInstructions; + public static int LIRInstructions; + public static int LIRVariables; + public static int LIRXIRInstructions; + public static int LIRMoveInstructions; + public static int LSRAIntervalsCreated; + public static int LSRASpills; + public static int LoadConstantIterations; + public static int CodeBufferCopies; + public static int UniqueValueIdsAssigned; + public static int FrameStatesCreated; + public static int FrameStateValuesCreated; + public static int NodesCanonicalized; + + public static void print() { + printClassFields(C1XMetrics.class); + + } + + public static void printClassFields(Class javaClass) { + final String className = javaClass.getSimpleName(); + TTY.println(className + " {"); + for (final Field field : javaClass.getFields()) { + printField(field, false); + } + TTY.println("}"); + } + + public static void printField(final Field field, boolean tabbed) { + final String fieldName = String.format("%35s", field.getName()); + try { + String prefix = tabbed ? "" : " " + fieldName + " = "; + String postfix = tabbed ? "\t" : "\n"; + if (field.getType() == int.class) { + TTY.print(prefix + field.getInt(null) + postfix); + } else if (field.getType() == boolean.class) { + TTY.print(prefix + field.getBoolean(null) + postfix); + } else if (field.getType() == float.class) { + TTY.print(prefix + field.getFloat(null) + postfix); + } else if (field.getType() == String.class) { + TTY.print(prefix + field.get(null) + postfix); + } else if (field.getType() == Map.class) { + Map m = (Map) field.get(null); + TTY.print(prefix + printMap(m) + postfix); + } else { + TTY.print(prefix + field.get(null) + postfix); + } + } catch (IllegalAccessException e) { + // do nothing. + } + } + + private static String printMap(Map m) { + StringBuilder sb = new StringBuilder(); + + List keys = new ArrayList(); + for (Object key : m.keySet()) { + keys.add((String) key); + } + Collections.sort(keys); + + for (String key : keys) { + sb.append(key); + sb.append("\t"); + sb.append(m.get(key)); + sb.append("\n"); + } + + return sb.toString(); + } + + private static void printField(String fieldName, long value) { + TTY.print(" " + fieldName + " = " + value + "\n"); + } + + private static void printField(String fieldName, double value) { + TTY.print(" " + fieldName + " = " + value + "\n"); + } +} + diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/C1XOptions.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/C1XOptions.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler; + +import com.oracle.max.graal.compiler.debug.TTY.*; + +/** + * This class encapsulates options that control the behavior of the C1X compiler. + * The help message for each option is specified by a {@linkplain #helpMap help map}. + * + * (tw) WARNING: Fields of this class are treated as final by Graal. + * + * @author Ben L. Titzer + */ +public final class C1XOptions { + + // Checkstyle: stop + private static final boolean ____ = false; + // Checkstyle: resume + + // inlining settings + public static boolean Inline = ____; + public static int MaximumInstructionCount = 37000; + public static float MaximumInlineRatio = 0.90f; + public static int MaximumInlineSize = 35; + public static int MaximumTrivialSize = 6; + public static int MaximumInlineLevel = 9; + public static int MaximumRecursiveInlineLevel = 2; + public static int MaximumDesiredSize = 8000; + public static int MaximumShortLoopSize = 5; + + // debugging settings + public static boolean VerifyPointerMaps = ____; + public static int MethodEndBreakpointGuards = 0; + public static boolean ZapStackOnMethodEntry = ____; + public static boolean StressLinearScan = ____; + public static boolean BailoutOnException = ____; + + /** + * See {@link Filter#Filter(String, Object)}. + */ + public static String PrintFilter = null; + + // printing settings + public static boolean PrintHIR = ____; + public static boolean PrintLIR = ____; + public static boolean PrintCFGToFile = ____; + + // DOT output settings + public static boolean PrintDOTGraphToFile = ____; + public static boolean PrintDOTGraphToPdf = ____; + public static boolean OmitDOTFrameStates = ____; + + // Ideal graph visualizer output settings + public static int PrintIdealGraphLevel = 0; + public static boolean PrintIdealGraphFile = ____; + public static String PrintIdealGraphAddress = "127.0.0.1"; + public static int PrintIdealGraphPort = 4444; + + // Other printing settings + public static boolean PrintMetrics = ____; + public static boolean PrintTimers = ____; + public static boolean PrintCompilation = ____; + public static boolean PrintXirTemplates = ____; + public static boolean PrintIRWithLIR = ____; + public static boolean PrintAssembly = ____; + public static boolean PrintCodeBytes = ____; + public static int PrintAssemblyBytesPerLine = 16; + public static int TraceLinearScanLevel = 0; + public static int TraceLIRGeneratorLevel = 0; + public static boolean TraceRelocation = ____; + public static boolean TraceLIRVisit = ____; + public static boolean TraceAssembler = ____; + public static boolean TraceInlining = ____; + public static boolean TraceDeadCodeElimination = ____; + public static int TraceBytecodeParserLevel = 0; + public static boolean QuietBailout = ____; + + // state merging settings + public static boolean AssumeVerifiedBytecode = ____; + + // Linear scan settings + public static boolean CopyPointerStackArguments = true; + + // Code generator settings + public static boolean GenLIR = true; + public static boolean GenCode = true; + + public static boolean UseConstDirectCall = false; + + public static boolean GenSpecialDivChecks = ____; + public static boolean GenAssertionCode = ____; + public static boolean AlignCallsForPatching = true; + public static boolean NullCheckUniquePc = ____; + public static boolean InvokeSnippetAfterArguments = ____; + public static boolean ResolveClassBeforeStaticInvoke = true; + + // Translating tableswitch instructions + public static int SequentialSwitchLimit = 4; + public static int RangeTestsSwitchDensity = 5; + + public static boolean DetailedAsserts = ____; + + // Runtime settings + public static int ReadPrefetchInstr = 0; + public static int StackShadowPages = 2; + + // Assembler settings + public static boolean CommentedAssembly = ____; + public static boolean PrintLIRWithAssembly = ____; + + public static boolean OptCanonicalizer = true; +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/C1XTimers.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/C1XTimers.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2009, 2009, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler; + +import com.oracle.max.graal.compiler.debug.*; + +/** + * This class contains timers that record the amount of time spent in various + * parts of the compiler. + * + * @author Christian Wimmer + */ +public enum C1XTimers { + HIR_CREATE("Create HIR"), + HIR_OPTIMIZE("Optimize HIR"), + NCE("Nullcheck elimination"), + LIR_CREATE("Create LIR"), + LIFETIME_ANALYSIS("Lifetime Analysis"), + LINEAR_SCAN("Linear Scan"), + RESOLUTION("Resolution"), + DEBUG_INFO("Create Debug Info"), + CODE_CREATE("Create Code"); + + private final String name; + private long start; + private long total; + + private C1XTimers(String name) { + this.name = name; + } + + public void start() { + start = System.nanoTime(); + } + + public void stop() { + total += System.nanoTime() - start; + } + + public static void reset() { + for (C1XTimers t : values()) { + t.total = 0; + } + } + + public static void print() { + long total = 0; + for (C1XTimers timer : C1XTimers.values()) { + total += timer.total; + } + if (total == 0) { + return; + } + + TTY.println(); + for (C1XTimers timer : C1XTimers.values()) { + TTY.println("%-20s: %7.4f s (%5.2f%%)", timer.name, timer.total / 1000000000.0, timer.total * 100.0 / total); + timer.total = 0; + } + TTY.println(); + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/ControlFlowOptimizer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/ControlFlowOptimizer.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,260 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.alloc; + +import java.util.*; + +import com.oracle.max.graal.compiler.*; +import com.oracle.max.graal.compiler.graph.*; +import com.oracle.max.graal.compiler.ir.*; +import com.oracle.max.graal.compiler.lir.*; +import com.oracle.max.graal.compiler.util.*; +import com.sun.cri.ci.*; + +/** + * This class performs basic optimizations on the control flow graph after LIR generation. + */ +final class ControlFlowOptimizer { + + /** + * Performs control flow optimizations on the given IR graph. + * @param ir the IR graph that should be optimized + */ + public static void optimize(IR ir) { + ControlFlowOptimizer optimizer = new ControlFlowOptimizer(ir); + List code = ir.linearScanOrder(); + optimizer.reorderShortLoops(code); + optimizer.deleteEmptyBlocks(code); + optimizer.deleteUnnecessaryJumps(code); + optimizer.deleteJumpsToReturn(code); + } + + private final IR ir; + + private ControlFlowOptimizer(IR ir) { + this.ir = ir; + } + + private void reorderShortLoop(List code, LIRBlock headerBlock, int headerIdx) { + int i = headerIdx + 1; + int maxEnd = Math.min(headerIdx + C1XOptions.MaximumShortLoopSize, code.size()); + while (i < maxEnd && code.get(i).loopDepth() >= headerBlock.loopDepth()) { + i++; + } + + if (i == code.size() || code.get(i).loopDepth() < headerBlock.loopDepth()) { + int endIdx = i - 1; + LIRBlock endBlock = code.get(endIdx); + + if (endBlock.numberOfSux() == 1 && endBlock.suxAt(0) == headerBlock) { + // short loop from headerIdx to endIdx found . reorder blocks such that + // the headerBlock is the last block instead of the first block of the loop + + for (int j = headerIdx; j < endIdx; j++) { + code.set(j, code.get(j + 1)); + } + code.set(endIdx, headerBlock); + } + } + } + + private void reorderShortLoops(List code) { + for (int i = code.size() - 1; i >= 0; i--) { + LIRBlock block = code.get(i); + + if (block.isLinearScanLoopHeader()) { + reorderShortLoop(code, block, i); + } + } + + assert verify(code); + } + + // only blocks with exactly one successor can be deleted. Such blocks + // must always end with an unconditional branch to this successor + private boolean canDeleteBlock(LIRBlock block) { + if (block.numberOfSux() != 1 || + block == ir.startBlock || + block.suxAt(0) == block) { + return false; + } + + List instructions = block.lir().instructionsList(); + + assert instructions.size() >= 2 : "block must have label and branch"; + assert instructions.get(0).code == LIROpcode.Label : "first instruction must always be a label"; + assert instructions.get(instructions.size() - 1) instanceof LIRBranch : "last instruction must always be a branch but is " + instructions.get(instructions.size() - 1); + assert ((LIRBranch) instructions.get(instructions.size() - 1)).cond() == Condition.TRUE : "branch must be unconditional"; + assert ((LIRBranch) instructions.get(instructions.size() - 1)).block() == block.suxAt(0) : "branch target must be the successor"; + + // block must have exactly one successor + + return instructions.size() == 2 && instructions.get(instructions.size() - 1).info == null; + } + + private void deleteEmptyBlocks(List code) { + int oldPos = 0; + int newPos = 0; + int numBlocks = code.size(); + + while (oldPos < numBlocks) { + LIRBlock block = code.get(oldPos); + + if (canDeleteBlock(block)) { + LIRBlock newTarget = block.suxAt(0); + + // update the block references in any branching LIR instructions + for (LIRBlock pred : block.blockPredecessors()) { + for (LIRInstruction instr : pred.lir().instructionsList()) { + if (instr instanceof LIRBranch) { + ((LIRBranch) instr).substitute(block, newTarget); + } else if (instr instanceof LIRTableSwitch) { + ((LIRTableSwitch) instr).substitute(block, newTarget); + } + } + } + + // adjust successor and predecessor lists + block.replaceWith(newTarget); + C1XMetrics.BlocksDeleted++; + } else { + // adjust position of this block in the block list if blocks before + // have been deleted + if (newPos != oldPos) { + code.set(newPos, code.get(oldPos)); + } + newPos++; + } + oldPos++; + } + assert verify(code); + Util.truncate(code, newPos); + + assert verify(code); + } + + private void deleteUnnecessaryJumps(List code) { + // skip the last block because there a branch is always necessary + for (int i = code.size() - 2; i >= 0; i--) { + LIRBlock block = code.get(i); + List instructions = block.lir().instructionsList(); + + LIRInstruction lastOp = instructions.get(instructions.size() - 1); + if (lastOp.code == LIROpcode.Branch) { + assert lastOp instanceof LIRBranch : "branch must be of type LIRBranch"; + LIRBranch lastBranch = (LIRBranch) lastOp; + + assert lastBranch.block() != null : "last branch must always have a block as target"; + assert lastBranch.label() == lastBranch.block().label() : "must be equal"; + + if (lastBranch.info == null) { + if (lastBranch.block() == code.get(i + 1)) { + // delete last branch instruction + Util.truncate(instructions, instructions.size() - 1); + + } else { + LIRInstruction prevOp = instructions.get(instructions.size() - 2); + if (prevOp.code == LIROpcode.Branch || prevOp.code == LIROpcode.CondFloatBranch) { + assert prevOp instanceof LIRBranch : "branch must be of type LIRBranch"; + LIRBranch prevBranch = (LIRBranch) prevOp; + + if (prevBranch.block() == code.get(i + 1) && prevBranch.info == null) { + // eliminate a conditional branch to the immediate successor + prevBranch.changeBlock(lastBranch.block()); + prevBranch.negateCondition(); + Util.truncate(instructions, instructions.size() - 1); + } + } + } + } + } + } + + assert verify(code); + } + + private void deleteJumpsToReturn(List code) { + for (int i = code.size() - 1; i >= 0; i--) { + LIRBlock block = code.get(i); + List curInstructions = block.lir().instructionsList(); + LIRInstruction curLastOp = curInstructions.get(curInstructions.size() - 1); + + assert curInstructions.get(0).code == LIROpcode.Label : "first instruction must always be a label"; + if (curInstructions.size() == 2 && curLastOp.code == LIROpcode.Return) { + // the block contains only a label and a return + // if a predecessor ends with an unconditional jump to this block, then the jump + // can be replaced with a return instruction + // + // Note: the original block with only a return statement cannot be deleted completely + // because the predecessors might have other (conditional) jumps to this block. + // this may lead to unnecesary return instructions in the final code + + assert curLastOp.info == null : "return instructions do not have debug information"; + + assert curLastOp instanceof LIROp1 : "return must be LIROp1"; + CiValue returnOpr = ((LIROp1) curLastOp).operand(); + + for (int j = block.numberOfPreds() - 1; j >= 0; j--) { + LIRBlock pred = block.predAt(j); + List predInstructions = pred.lir().instructionsList(); + LIRInstruction predLastOp = predInstructions.get(predInstructions.size() - 1); + + if (predLastOp.code == LIROpcode.Branch) { + assert predLastOp instanceof LIRBranch : "branch must be LIRBranch"; + LIRBranch predLastBranch = (LIRBranch) predLastOp; + + if (predLastBranch.block() == block && predLastBranch.cond() == Condition.TRUE && predLastBranch.info == null) { + // replace the jump to a return with a direct return + // Note: currently the edge between the blocks is not deleted + predInstructions.set(predInstructions.size() - 1, new LIROp1(LIROpcode.Return, returnOpr)); + } + } + } + } + } + } + + private boolean verify(List code) { + for (LIRBlock block : code) { + List instructions = block.lir().instructionsList(); + + for (LIRInstruction instr : instructions) { + if (instr instanceof LIRBranch) { + LIRBranch opBranch = (LIRBranch) instr; + assert opBranch.block() == null || code.contains(opBranch.block()) : "missing successor branch from: " + block + " to: " + opBranch.block(); + assert opBranch.unorderedBlock() == null || code.contains(opBranch.unorderedBlock()) : "missing successor branch from: " + block + " to: " + opBranch.unorderedBlock(); + } + } + + for (LIRBlock sux : block.blockSuccessors()) { + assert code.contains(sux) : "missing successor from: " + block + "to: " + sux; + } + + for (LIRBlock pred : block.blockPredecessors()) { + assert code.contains(pred) : "missing predecessor from: " + block + "to: " + pred; + } + } + + return true; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/EdgeMoveOptimizer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/EdgeMoveOptimizer.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,298 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.alloc; + +import java.util.*; + +import com.oracle.max.graal.compiler.*; +import com.oracle.max.graal.compiler.ir.*; +import com.oracle.max.graal.compiler.lir.*; + +/** + * This class optimizes moves, particularly those that result from eliminating SSA form. + * + * When a block has more than one predecessor, and all predecessors end with + * the {@linkplain #same(LIRInstruction, LIRInstruction) same} sequence of + * {@linkplain LIROpcode#Move move} instructions, then these sequences + * can be replaced with a single copy of the sequence at the beginning of the block. + * + * Similarly, when a block has more than one successor, then same sequences of + * moves at the beginning of the successors can be placed once at the end of + * the block. But because the moves must be inserted before all branch + * instructions, this works only when there is exactly one conditional branch + * at the end of the block (because the moves must be inserted before all + * branches, but after all compares). + * + * This optimization affects all kind of moves (reg->reg, reg->stack and + * stack->reg). Because this optimization works best when a block contains only + * a few moves, it has a huge impact on the number of blocks that are totally + * empty. + * + * @author Christian Wimmer (original HotSpot implementation) + * @author Thomas Wuerthinger + * @author Doug Simon + */ +final class EdgeMoveOptimizer { + + /** + * Optimizes moves on block edges. + * + * @param blockList a list of blocks whose moves should be optimized + */ + public static void optimize(List blockList) { + EdgeMoveOptimizer optimizer = new EdgeMoveOptimizer(); + + // ignore the first block in the list (index 0 is not processed) + for (int i = blockList.size() - 1; i >= 1; i--) { + LIRBlock block = blockList.get(i); + + if (block.numberOfPreds() > 1) { + optimizer.optimizeMovesAtBlockEnd(block); + } + if (block.numberOfSux() == 2) { + optimizer.optimizeMovesAtBlockBegin(block); + } + } + } + + private final List> edgeInstructionSeqences; + + private EdgeMoveOptimizer() { + edgeInstructionSeqences = new ArrayList>(4); + } + + /** + * Determines if two operations are both {@linkplain LIROpcode#Move moves} + * that have the same {@linkplain LIROp1#operand() source} and {@linkplain LIROp1#result() destination} + * operands and they have the same {@linkplain LIRInstruction#info debug info}. + * + * @param op1 the first instruction to compare + * @param op2 the second instruction to compare + * @return {@code true} if {@code op1} and {@code op2} are the same by the above algorithm + */ + private boolean same(LIRInstruction op1, LIRInstruction op2) { + assert op1 != null; + assert op2 != null; + + if (op1.code == LIROpcode.Move && op2.code == LIROpcode.Move) { + assert op1 instanceof LIROp1 : "move must be LIROp1"; + assert op2 instanceof LIROp1 : "move must be LIROp1"; + LIROp1 move1 = (LIROp1) op1; + LIROp1 move2 = (LIROp1) op2; + if (move1.info == move2.info && move1.operand().equals(move2.operand()) && move1.result().equals(move2.result())) { + // these moves are exactly equal and can be optimized + return true; + } + } + return false; + } + + /** + * Moves the longest {@linkplain #same common} subsequence at the end all + * predecessors of {@code block} to the start of {@code block}. + */ + private void optimizeMovesAtBlockEnd(LIRBlock block) { + if (block.isPredecessor(block)) { + // currently we can't handle this correctly. + return; + } + + // clear all internal data structures + edgeInstructionSeqences.clear(); + + int numPreds = block.numberOfPreds(); + assert numPreds > 1 : "do not call otherwise"; + + // setup a list with the LIR instructions of all predecessors + for (int i = 0; i < numPreds; i++) { + LIRBlock pred = block.predAt(i); + assert pred != null; + assert pred.lir() != null; + List predInstructions = pred.lir().instructionsList(); + + if (pred.numberOfSux() != 1) { + // this can happen with switch-statements where multiple edges are between + // the same blocks. + return; + } + + assert pred.suxAt(0) == block : "invalid control flow"; + assert predInstructions.get(predInstructions.size() - 1).code == LIROpcode.Branch : "block with successor must end with branch"; + assert predInstructions.get(predInstructions.size() - 1) instanceof LIRBranch : "branch must be LIROpBranch"; + assert ((LIRBranch) predInstructions.get(predInstructions.size() - 1)).cond() == Condition.TRUE : "block must end with unconditional branch"; + + if (predInstructions.get(predInstructions.size() - 1).info != null) { + // can not optimize instructions that have debug info + return; + } + + // ignore the unconditional branch at the end of the block + List seq = predInstructions.subList(0, predInstructions.size() - 1); + edgeInstructionSeqences.add(seq); + } + + // process lir-instructions while all predecessors end with the same instruction + while (true) { + List seq = edgeInstructionSeqences.get(0); + if (seq.isEmpty()) { + return; + } + + LIRInstruction op = last(seq); + for (int i = 1; i < numPreds; ++i) { + List otherSeq = edgeInstructionSeqences.get(i); + if (otherSeq.isEmpty() || !same(op, last(otherSeq))) { + return; + } + } + + // insert the instruction at the beginning of the current block + block.lir().insertBefore(1, op); + + // delete the instruction at the end of all predecessors + for (int i = 0; i < numPreds; i++) { + seq = edgeInstructionSeqences.get(i); + removeLast(seq); + } + } + } + + /** + * Moves the longest {@linkplain #same common} subsequence at the start of all + * successors of {@code block} to the end of {@code block} just prior to the + * branch instruction ending {@code block}. + */ + private void optimizeMovesAtBlockBegin(LIRBlock block) { + + edgeInstructionSeqences.clear(); + int numSux = block.numberOfSux(); + + List instructions = block.lir().instructionsList(); + + assert numSux == 2 : "method should not be called otherwise"; + assert instructions.get(instructions.size() - 1).code == LIROpcode.Branch : "block with successor must end with branch block=B" + block.blockID(); + assert instructions.get(instructions.size() - 1) instanceof LIRBranch : "branch must be LIROpBranch"; + assert ((LIRBranch) instructions.get(instructions.size() - 1)).cond() == Condition.TRUE : "block must end with unconditional branch"; + + if (instructions.get(instructions.size() - 1).info != null) { + // cannot optimize instructions when debug info is needed + return; + } + + LIRInstruction branch = instructions.get(instructions.size() - 2); + if (branch.info != null || (branch.code != LIROpcode.Branch && branch.code != LIROpcode.CondFloatBranch)) { + // not a valid case for optimization + // currently, only blocks that end with two branches (conditional branch followed + // by unconditional branch) are optimized + return; + } + + // now it is guaranteed that the block ends with two branch instructions. + // the instructions are inserted at the end of the block before these two branches + int insertIdx = instructions.size() - 2; + + if (C1XOptions.DetailedAsserts) { + for (int i = insertIdx - 1; i >= 0; i--) { + LIRInstruction op = instructions.get(i); + if ((op.code == LIROpcode.Branch || op.code == LIROpcode.CondFloatBranch) && ((LIRBranch) op).block() != null) { + throw new Error("block with two successors can have only two branch instructions"); + } + } + } + + // setup a list with the lir-instructions of all successors + for (int i = 0; i < numSux; i++) { + LIRBlock sux = block.suxAt(i); + List suxInstructions = sux.lir().instructionsList(); + + assert suxInstructions.get(0).code == LIROpcode.Label : "block must start with label"; + + if (sux.numberOfPreds() != 1) { + // this can happen with switch-statements where multiple edges are between + // the same blocks. + return; + } + assert sux.predAt(0) == block : "invalid control flow"; + + // ignore the label at the beginning of the block + List seq = suxInstructions.subList(1, suxInstructions.size()); + edgeInstructionSeqences.add(seq); + } + + // process LIR instructions while all successors begin with the same instruction + while (true) { + List seq = edgeInstructionSeqences.get(0); + if (seq.isEmpty()) { + return; + } + + LIRInstruction op = first(seq); + for (int i = 1; i < numSux; i++) { + List otherSeq = edgeInstructionSeqences.get(i); + if (otherSeq.isEmpty() || !same(op, first(otherSeq))) { + // these instructions are different and cannot be optimized . + // no further optimization possible + return; + } + } + + // insert instruction at end of current block + block.lir().insertBefore(insertIdx, op); + insertIdx++; + + // delete the instructions at the beginning of all successors + for (int i = 0; i < numSux; i++) { + seq = edgeInstructionSeqences.get(i); + removeFirst(seq); + } + } + } + + /** + * Gets the first element from a LIR instruction sequence. + */ + private static LIRInstruction first(List seq) { + return seq.get(0); + } + + /** + * Gets the last element from a LIR instruction sequence. + */ + private static LIRInstruction last(List seq) { + return seq.get(seq.size() - 1); + } + + /** + * Removes the first element from a LIR instruction sequence. + */ + private static void removeFirst(List seq) { + seq.remove(0); + } + + /** + * Removes the last element from a LIR instruction sequence. + */ + private static void removeLast(List seq) { + seq.remove(seq.size() - 1); + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/Interval.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/Interval.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,1173 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.alloc; + +import java.util.*; + +import com.oracle.max.graal.compiler.*; +import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.compiler.lir.*; +import com.oracle.max.graal.compiler.util.*; +import com.sun.cri.ci.*; + +/** + * Represents an interval in the {@linkplain LinearScan linear scan register allocator}. + * + * @author Thomas Wuerthinger + * @author Doug Simon + */ +public final class Interval { + + /** + * A pair of intervals. + */ + static final class Pair { + public final Interval first; + public final Interval second; + public Pair(Interval first, Interval second) { + this.first = first; + this.second = second; + } + } + + /** + * A set of interval lists, one per {@linkplain RegisterBinding binding} type. + */ + static final class RegisterBindingLists { + + /** + * List of intervals whose binding is currently {@link RegisterBinding#Fixed}. + */ + public Interval fixed; + + /** + * List of intervals whose binding is currently {@link RegisterBinding#Any}. + */ + public Interval any; + + public RegisterBindingLists(Interval fixed, Interval any) { + this.fixed = fixed; + this.any = any; + } + + /** + * Gets the list for a specified binding. + * + * @param binding specifies the list to be returned + * @return the list of intervals whose binding is {@code binding} + */ + public Interval get(RegisterBinding binding) { + if (binding == RegisterBinding.Any) { + return any; + } + assert binding == RegisterBinding.Fixed; + return fixed; + } + + /** + * Sets the list for a specified binding. + * + * @param binding specifies the list to be replaced + * @param a list of intervals whose binding is {@code binding} + */ + public void set(RegisterBinding binding, Interval list) { + assert list != null; + if (binding == RegisterBinding.Any) { + any = list; + } else { + assert binding == RegisterBinding.Fixed; + fixed = list; + } + } + + /** + * Adds an interval to a list sorted by {@linkplain Interval#currentFrom() current from} positions. + * + * @param binding specifies the list to be updated + * @param interval the interval to add + */ + public void addToListSortedByCurrentFromPositions(RegisterBinding binding, Interval interval) { + Interval list = get(binding); + Interval prev = null; + Interval cur = list; + while (cur.currentFrom() < interval.currentFrom()) { + prev = cur; + cur = cur.next; + } + Interval result = list; + if (prev == null) { + // add to head of list + result = interval; + } else { + // add before 'cur' + prev.next = interval; + } + interval.next = cur; + set(binding, result); + } + + /** + * Adds an interval to a list sorted by {@linkplain Interval#from() start} positions and + * {@linkplain Interval#firstUsage(RegisterPriority) first usage} positions. + * + * @param binding specifies the list to be updated + * @param interval the interval to add + */ + public void addToListSortedByStartAndUsePositions(RegisterBinding binding, Interval interval) { + Interval list = get(binding); + Interval prev = null; + Interval cur = list; + while (cur.from() < interval.from() || (cur.from() == interval.from() && cur.firstUsage(RegisterPriority.None) < interval.firstUsage(RegisterPriority.None))) { + prev = cur; + cur = cur.next; + } + if (prev == null) { + list = interval; + } else { + prev.next = interval; + } + interval.next = cur; + set(binding, list); + } + + /** + * Removes an interval from a list. + * + * @param binding specifies the list to be updated + * @param interval the interval to remove + */ + public void remove(RegisterBinding binding, Interval i) { + Interval list = get(binding); + Interval prev = null; + Interval cur = list; + while (cur != i) { + assert cur != null && cur != Interval.EndMarker : "interval has not been found in list: " + i; + prev = cur; + cur = cur.next; + } + if (prev == null) { + set(binding, cur.next); + } else { + prev.next = cur.next; + } + } + } + + /** + * Constants denoting the register usage priority for an interval. + * The constants are declared in increasing order of priority are + * are used to optimize spilling when multiple overlapping intervals + * compete for limited registers. + */ + enum RegisterPriority { + /** + * No special reason for an interval to be allocated a register. + */ + None, + + /** + * Priority level for intervals live at the end of a loop. + */ + LiveAtLoopEnd, + + /** + * Priority level for intervals that should be allocated to a register. + */ + ShouldHaveRegister, + + /** + * Priority level for intervals that must be allocated to a register. + */ + MustHaveRegister; + + public static final RegisterPriority[] VALUES = values(); + + /** + * Determines if this priority is higher than or equal to a given priority. + */ + public boolean greaterEqual(RegisterPriority other) { + return ordinal() >= other.ordinal(); + } + + /** + * Determines if this priority is lower than a given priority. + */ + public boolean lessThan(RegisterPriority other) { + return ordinal() < other.ordinal(); + } + } + + /** + * Constants denoting whether an interval is bound to a specific register. This models + * platform dependencies on register usage for certain instructions. + */ + enum RegisterBinding { + /** + * Interval is bound to a specific register as required by the platform. + */ + Fixed, + + /** + * Interval has no specific register requirements. + */ + Any; + + public static final RegisterBinding[] VALUES = values(); + } + + /** + * Constants denoting the linear-scan states an interval may be in with respect to the + * {@linkplain Interval#from() start} {@code position} of the interval being processed. + */ + enum State { + /** + * An interval that starts after {@code position}. + */ + Unhandled, + + /** + * An interval that {@linkplain Interval#covers covers} {@code position} and has an assigned register. + */ + Active, + + /** + * An interval that starts before and ends after {@code position} but does not + * {@linkplain Interval#covers cover} it due to a lifetime hole. + */ + Inactive, + + /** + * An interval that ends before {@code position} or is spilled to memory. + */ + Handled; + } + + /** + * Constants used in optimization of spilling of an interval. + */ + enum SpillState { + /** + * Starting state of calculation: no definition found yet. + */ + NoDefinitionFound, + + /** + * One definition has already been found. Two consecutive definitions are treated as one + * (e.g. a consecutive move and add because of two-operand LIR form). + * The position of this definition is given by {@link Interval#spillDefinitionPos()}. + */ + NoSpillStore, + + /** + * One spill move has already been inserted. + */ + OneSpillStore, + + /** + * The interval should be stored immediately after its definition to prevent + * multiple redundant stores. + */ + StoreAtDefinition, + + /** + * The interval starts in memory (e.g. method parameter), so a store is never necessary. + */ + StartInMemory, + + /** + * The interval has more than one definition (e.g. resulting from phi moves), so stores + * to memory are not optimized. + */ + NoOptimization + } + + /** + * List of use positions. Each entry in the list records the use position and register + * priority associated with the use position. The entries in the list are in descending + * order of use position. + * + * @author Doug Simon + */ + public static final class UsePosList { + private IntList list; + + /** + * Creates a use list. + * + * @param initialCapacity the initial capacity of the list in terms of entries + */ + public UsePosList(int initialCapacity) { + list = new IntList(initialCapacity * 2); + } + + private UsePosList(IntList list) { + this.list = list; + } + + /** + * Splits this list around a given position. All entries in this list with a use position greater or equal than + * {@code splitPos} are removed from this list and added to the returned list. + * + * @param splitPos the position for the split + * @return a use position list containing all entries removed from this list that have a use position greater or equal + * than {@code splitPos} + */ + public UsePosList splitAt(int splitPos) { + int i = size() - 1; + int len = 0; + while (i >= 0 && usePos(i) < splitPos) { + --i; + len += 2; + } + int listSplitIndex = (i + 1) * 2; + IntList childList = list; + list = IntList.copy(this.list, listSplitIndex, len); + childList.setSize(listSplitIndex); + UsePosList child = new UsePosList(childList); + return child; + } + + /** + * Gets the use position at a specified index in this list. + * + * @param index the index of the entry for which the use position is returned + * @return the use position of entry {@code index} in this list + */ + public int usePos(int index) { + return list.get(index << 1); + } + + /** + * Gets the register priority for the use position at a specified index in this list. + * + * @param index the index of the entry for which the register priority is returned + * @return the register priority of entry {@code index} in this list + */ + public RegisterPriority registerPriority(int index) { + return RegisterPriority.VALUES[list.get((index << 1) + 1)]; + } + + public void add(int usePos, RegisterPriority registerPriority) { + assert list.size() == 0 || usePos(size() - 1) > usePos; + list.add(usePos); + list.add(registerPriority.ordinal()); + } + + public int size() { + return list.size() >> 1; + } + + public void removeLowestUsePos() { + list.setSize(list.size() - 2); + } + + public void setRegisterPriority(int index, RegisterPriority registerPriority) { + list.set(index * 2, registerPriority.ordinal()); + } + + @Override + public String toString() { + StringBuilder buf = new StringBuilder("["); + for (int i = size() - 1; i >= 0; --i) { + if (buf.length() != 1) { + buf.append(", "); + } + RegisterPriority prio = registerPriority(i); + buf.append(usePos(i)).append(" -> ").append(prio.ordinal()).append(':').append(prio); + } + return buf.append("]").toString(); + } + } + + /** + * The {@linkplain CiRegisterValue register} or {@linkplain CiVariable variable} for this interval prior to register allocation. + */ + public final CiValue operand; + + /** + * The {@linkplain OperandPool#operandNumber(CiValue) operand number} for this interval's {@linkplain #operand operand}. + */ + public final int operandNumber; + + /** + * The {@linkplain CiRegisterValue register}, {@linkplain CiStackSlot spill slot} or {@linkplain CiAddress address} assigned to this interval. + */ + private CiValue location; + + /** + * The stack slot to which all splits of this interval are spilled if necessary. + */ + private CiStackSlot spillSlot; + + /** + * The kind of this interval. + * Only valid if this is a {@linkplain #isVariable() variable}. + */ + private CiKind kind; + + /** + * The head of the list of ranges describing this interval. This list is sorted by {@linkplain LIRInstruction#id instruction ids}. + */ + private Range first; + + /** + * List of (use-positions, register-priorities) pairs, sorted by use-positions. + */ + private UsePosList usePosList; + + /** + * Iterator used to traverse the ranges of an interval. + */ + private Range current; + + /** + * Link to next interval in a sorted list of intervals that ends with {@link #EndMarker}. + */ + Interval next; + + /** + * The linear-scan state of this interval. + */ + State state; + + private int cachedTo; // cached value: to of last range (-1: not cached) + + /** + * The interval from which this one is derived. If this is a {@linkplain #isSplitParent() split parent}, it points to itself. + */ + private Interval splitParent; + + /** + * List of all intervals that are split off from this interval. This is only used if this is a {@linkplain #isSplitParent() split parent}. + */ + private List splitChildren = Collections.emptyList(); + + /** + * Current split child that has been active or inactive last (always stored in split parents). + */ + private Interval currentSplitChild; + + /** + * Specifies if move is inserted between currentSplitChild and this interval when interval gets active the first time. + */ + private boolean insertMoveWhenActivated; + + /** + * For spill move optimization. + */ + private SpillState spillState; + + /** + * Position where this interval is defined (if defined only once). + */ + private int spillDefinitionPos; + + /** + * This interval should be assigned the same location as the hint interval. + */ + private Interval locationHint; + + void assignLocation(CiValue location) { + if (location.isRegister()) { + assert this.location == null : "cannot re-assign location for " + this; + if (location.kind == CiKind.Illegal && kind != CiKind.Illegal) { + location = location.asRegister().asValue(kind); + } + } else { + assert this.location == null || this.location.isRegister() : "cannot re-assign location for " + this; + assert location.isStackSlot(); + assert location.kind != CiKind.Illegal; + assert location.kind == this.kind; + } + this.location = location; + } + + /** + * Gets the {@linkplain CiRegisterValue register}, {@linkplain CiStackSlot spill slot} or {@linkplain CiAddress address} assigned to this interval. + */ + public CiValue location() { + return location; + } + + public CiKind kind() { + assert !operand.isRegister() : "cannot access type for fixed interval"; + return kind; + } + + void setKind(CiKind kind) { + assert operand.isRegister() || this.kind == CiKind.Illegal || this.kind == kind : "overwriting existing type"; + assert kind == kind.stackKind() || kind == CiKind.Short : "these kinds should have int type registers"; + this.kind = kind; + } + + public Range first() { + return first; + } + + int from() { + return first.from; + } + + int to() { + if (cachedTo == -1) { + cachedTo = calcTo(); + } + assert cachedTo == calcTo() : "invalid cached value"; + return cachedTo; + } + + int numUsePositions() { + return usePosList.size(); + } + + void setLocationHint(Interval interval) { + locationHint = interval; + } + + boolean isSplitParent() { + return splitParent == this; + } + + boolean isSplitChild() { + return splitParent != this; + } + + /** + * Gets the split parent for this interval. + */ + public Interval splitParent() { + assert splitParent.isSplitParent() : "not a split parent: " + this; + return splitParent; + } + + /** + * Gets the canonical spill slot for this interval. + */ + CiStackSlot spillSlot() { + return splitParent().spillSlot; + } + + void setSpillSlot(CiStackSlot slot) { + assert splitParent().spillSlot == null : "connot overwrite existing spill slot"; + splitParent().spillSlot = slot; + } + + Interval currentSplitChild() { + return splitParent().currentSplitChild; + } + + void makeCurrentSplitChild() { + splitParent().currentSplitChild = this; + } + + boolean insertMoveWhenActivated() { + return insertMoveWhenActivated; + } + + void setInsertMoveWhenActivated(boolean b) { + insertMoveWhenActivated = b; + } + + // for spill optimization + public SpillState spillState() { + return splitParent().spillState; + } + + int spillDefinitionPos() { + return splitParent().spillDefinitionPos; + } + + void setSpillState(SpillState state) { + assert state.ordinal() >= spillState().ordinal() : "state cannot decrease"; + splitParent().spillState = state; + } + + void setSpillDefinitionPos(int pos) { + assert spillDefinitionPos() == -1 : "cannot set the position twice"; + splitParent().spillDefinitionPos = pos; + } + + // returns true if this interval has a shadow copy on the stack that is always correct + boolean alwaysInMemory() { + return splitParent().spillState == SpillState.StoreAtDefinition || splitParent().spillState == SpillState.StartInMemory; + } + + void removeFirstUsePos() { + usePosList.removeLowestUsePos(); + } + + // test intersection + boolean intersects(Interval i) { + return first.intersects(i.first); + } + + int intersectsAt(Interval i) { + return first.intersectsAt(i.first); + } + + // range iteration + void rewindRange() { + current = first; + } + + void nextRange() { + assert this != EndMarker : "not allowed on sentinel"; + current = current.next; + } + + int currentFrom() { + return current.from; + } + + int currentTo() { + return current.to; + } + + boolean currentAtEnd() { + return current == Range.EndMarker; + } + + boolean currentIntersects(Interval it) { + return current.intersects(it.current); + } + + int currentIntersectsAt(Interval it) { + return current.intersectsAt(it.current); + } + + /** + * Sentinel interval to denote the end of an interval list. + */ + static final Interval EndMarker = new Interval(CiValue.IllegalValue, -1); + + Interval(CiValue operand, int operandNumber) { + C1XMetrics.LSRAIntervalsCreated++; + assert operand != null; + this.operand = operand; + this.operandNumber = operandNumber; + if (operand.isRegister()) { + location = operand; + } else { + assert operand.isIllegal() || operand.isVariable(); + } + this.kind = CiKind.Illegal; + this.first = Range.EndMarker; + this.usePosList = new UsePosList(4); + this.current = Range.EndMarker; + this.next = EndMarker; + this.cachedTo = -1; + this.spillState = SpillState.NoDefinitionFound; + this.spillDefinitionPos = -1; + splitParent = this; + currentSplitChild = this; + } + + int calcTo() { + assert first != Range.EndMarker : "interval has no range"; + + Range r = first; + while (r.next != Range.EndMarker) { + r = r.next; + } + return r.to; + } + + // consistency check of split-children + boolean checkSplitChildren() { + if (!splitChildren.isEmpty()) { + assert isSplitParent() : "only split parents can have children"; + + for (int i = 0; i < splitChildren.size(); i++) { + Interval i1 = splitChildren.get(i); + + assert i1.splitParent() == this : "not a split child of this interval"; + assert i1.kind() == kind() : "must be equal for all split children"; + assert i1.spillSlot() == spillSlot() : "must be equal for all split children"; + + for (int j = i + 1; j < splitChildren.size(); j++) { + Interval i2 = splitChildren.get(j); + + assert i1.operand != i2.operand : "same register number"; + + if (i1.from() < i2.from()) { + assert i1.to() <= i2.from() && i1.to() < i2.to() : "intervals overlapping"; + } else { + assert i2.from() < i1.from() : "intervals start at same opId"; + assert i2.to() <= i1.from() && i2.to() < i1.to() : "intervals overlapping"; + } + } + } + } + + return true; + } + + public Interval locationHint(boolean searchSplitChild, LinearScan allocator) { + if (!searchSplitChild) { + return locationHint; + } + + if (locationHint != null) { + assert locationHint.isSplitParent() : "ony split parents are valid hint registers"; + + if (locationHint.location != null && locationHint.location.isRegister()) { + return locationHint; + } else if (!locationHint.splitChildren.isEmpty()) { + // search the first split child that has a register assigned + int len = locationHint.splitChildren.size(); + for (int i = 0; i < len; i++) { + Interval interval = locationHint.splitChildren.get(i); + if (interval.location != null && interval.location.isRegister()) { + return interval; + } + } + } + } + + // no hint interval found that has a register assigned + return null; + } + + Interval getSplitChildAtOpId(int opId, LIRInstruction.OperandMode mode, LinearScan allocator) { + assert isSplitParent() : "can only be called for split parents"; + assert opId >= 0 : "invalid opId (method cannot be called for spill moves)"; + + if (splitChildren.isEmpty()) { + assert this.covers(opId, mode) : this + " does not cover " + opId; + return this; + } else { + Interval result = null; + int len = splitChildren.size(); + + // in outputMode, the end of the interval (opId == cur.to()) is not valid + int toOffset = (mode == LIRInstruction.OperandMode.Output ? 0 : 1); + + int i; + for (i = 0; i < len; i++) { + Interval cur = splitChildren.get(i); + if (cur.from() <= opId && opId < cur.to() + toOffset) { + if (i > 0) { + // exchange current split child to start of list (faster access for next call) + Util.atPutGrow(splitChildren, i, splitChildren.get(0), null); + Util.atPutGrow(splitChildren, 0, cur, null); + } + + // interval found + result = cur; + break; + } + } + + assert checkSplitChild(result, opId, allocator, toOffset, mode); + return result; + } + } + + private boolean checkSplitChild(Interval result, int opId, LinearScan allocator, int toOffset, LIRInstruction.OperandMode mode) { + if (result == null) { + // this is an error + StringBuilder msg = new StringBuilder(this.toString()).append(" has no child at ").append(opId); + if (!splitChildren.isEmpty()) { + Interval first = splitChildren.get(0); + Interval last = splitChildren.get(splitChildren.size() - 1); + msg.append(" (first = ").append(first).append(", last = ").append(last).append(")"); + } + throw new CiBailout("Linear Scan Error: " + msg); + } + + if (!splitChildren.isEmpty()) { + for (Interval interval : splitChildren) { + if (interval != result && interval.from() <= opId && opId < interval.to() + toOffset) { + TTY.println(String.format("two valid result intervals found for opId %d: %d and %d", opId, result.operandNumber, interval.operandNumber)); + TTY.println(result.logString(allocator)); + TTY.println(interval.logString(allocator)); + throw new CiBailout("two valid result intervals found"); + } + } + } + assert result.covers(opId, mode) : "opId not covered by interval"; + return true; + } + + // returns the last split child that ends before the given opId + Interval getSplitChildBeforeOpId(int opId) { + assert opId >= 0 : "invalid opId"; + + Interval parent = splitParent(); + Interval result = null; + + assert !parent.splitChildren.isEmpty() : "no split children available"; + int len = parent.splitChildren.size(); + + for (int i = len - 1; i >= 0; i--) { + Interval cur = parent.splitChildren.get(i); + if (cur.to() <= opId && (result == null || result.to() < cur.to())) { + result = cur; + } + } + + assert result != null : "no split child found"; + return result; + } + + // checks if opId is covered by any split child + boolean splitChildCovers(int opId, LIRInstruction.OperandMode mode) { + assert isSplitParent() : "can only be called for split parents"; + assert opId >= 0 : "invalid opId (method can not be called for spill moves)"; + + if (splitChildren.isEmpty()) { + // simple case if interval was not split + return covers(opId, mode); + + } else { + // extended case: check all split children + int len = splitChildren.size(); + for (int i = 0; i < len; i++) { + Interval cur = splitChildren.get(i); + if (cur.covers(opId, mode)) { + return true; + } + } + return false; + } + } + + // Note: use positions are sorted descending . first use has highest index + int firstUsage(RegisterPriority minRegisterPriority) { + assert operand.isVariable() : "cannot access use positions for fixed intervals"; + + for (int i = usePosList.size() - 1; i >= 0; --i) { + RegisterPriority registerPriority = usePosList.registerPriority(i); + if (registerPriority.greaterEqual(minRegisterPriority)) { + return usePosList.usePos(i); + } + } + return Integer.MAX_VALUE; + } + + int nextUsage(RegisterPriority minRegisterPriority, int from) { + assert operand.isVariable() : "cannot access use positions for fixed intervals"; + + for (int i = usePosList.size() - 1; i >= 0; --i) { + int usePos = usePosList.usePos(i); + if (usePos >= from && usePosList.registerPriority(i).greaterEqual(minRegisterPriority)) { + return usePos; + } + } + return Integer.MAX_VALUE; + } + + int nextUsageExact(RegisterPriority exactRegisterPriority, int from) { + assert operand.isVariable() : "cannot access use positions for fixed intervals"; + + for (int i = usePosList.size() - 1; i >= 0; --i) { + int usePos = usePosList.usePos(i); + if (usePos >= from && usePosList.registerPriority(i) == exactRegisterPriority) { + return usePos; + } + } + return Integer.MAX_VALUE; + } + + int previousUsage(RegisterPriority minRegisterPriority, int from) { + assert operand.isVariable() : "cannot access use positions for fixed intervals"; + + int prev = 0; + for (int i = usePosList.size() - 1; i >= 0; --i) { + int usePos = usePosList.usePos(i); + if (usePos > from) { + return prev; + } + if (usePosList.registerPriority(i).greaterEqual(minRegisterPriority)) { + prev = usePos; + } + } + return prev; + } + + void addUsePos(int pos, RegisterPriority registerPriority) { + assert covers(pos, LIRInstruction.OperandMode.Input) : "use position not covered by live range"; + + // do not add use positions for precolored intervals because they are never used + if (registerPriority != RegisterPriority.None && operand.isVariable()) { + if (C1XOptions.DetailedAsserts) { + for (int i = 0; i < usePosList.size(); i++) { + assert pos <= usePosList.usePos(i) : "already added a use-position with lower position"; + if (i > 0) { + assert usePosList.usePos(i) < usePosList.usePos(i - 1) : "not sorted descending"; + } + } + } + + // Note: addUse is called in descending order, so list gets sorted + // automatically by just appending new use positions + int len = usePosList.size(); + if (len == 0 || usePosList.usePos(len - 1) > pos) { + usePosList.add(pos, registerPriority); + } else if (usePosList.registerPriority(len - 1).lessThan(registerPriority)) { + assert usePosList.usePos(len - 1) == pos : "list not sorted correctly"; + usePosList.setRegisterPriority(len - 1, registerPriority); + } + } + } + + void addRange(int from, int to) { + assert from < to : "invalid range"; + assert first() == Range.EndMarker || to < first().next.from : "not inserting at begin of interval"; + assert from <= first().to : "not inserting at begin of interval"; + + if (first.from <= to) { + assert first != Range.EndMarker; + // join intersecting ranges + first.from = Math.min(from, first().from); + first.to = Math.max(to, first().to); + } else { + // insert new range + first = new Range(from, to, first()); + } + } + + Interval newSplitChild(LinearScan allocator) { + // allocate new interval + Interval parent = splitParent(); + Interval result = allocator.createDerivedInterval(parent); + result.setKind(kind()); + + result.splitParent = parent; + result.setLocationHint(parent); + + // insert new interval in children-list of parent + if (parent.splitChildren.isEmpty()) { + assert isSplitParent() : "list must be initialized at first split"; + + // Create new non-shared list + parent.splitChildren = new ArrayList(4); + parent.splitChildren.add(this); + } + parent.splitChildren.add(result); + + return result; + } + + /** + * Splits this interval at a specified position and returns the remainder as a new child interval + * of this interval's {@linkplain #splitParent() parent} interval. + *

+ * When an interval is split, a bi-directional link is established between the original parent + * interval and the children intervals that are split off this interval. + * When a split child is split again, the new created interval is a direct child + * of the original parent. That is, there is no tree of split children stored, just a flat list. + * All split children are spilled to the same {@linkplain #spillSlot spill slot}. + * + * @param splitPos the position at which to split this interval + * @param allocator the register allocator context + * @return the child interval split off from this interval + */ + Interval split(int splitPos, LinearScan allocator) { + assert operand.isVariable() : "cannot split fixed intervals"; + + // allocate new interval + Interval result = newSplitChild(allocator); + + // split the ranges + Range prev = null; + Range cur = first; + while (cur != Range.EndMarker && cur.to <= splitPos) { + prev = cur; + cur = cur.next; + } + assert cur != Range.EndMarker : "split interval after end of last range"; + + if (cur.from < splitPos) { + result.first = new Range(splitPos, cur.to, cur.next); + cur.to = splitPos; + cur.next = Range.EndMarker; + + } else { + assert prev != null : "split before start of first range"; + result.first = cur; + prev.next = Range.EndMarker; + } + result.current = result.first; + cachedTo = -1; // clear cached value + + // split list of use positions + result.usePosList = usePosList.splitAt(splitPos); + + if (C1XOptions.DetailedAsserts) { + for (int i = 0; i < usePosList.size(); i++) { + assert usePosList.usePos(i) < splitPos; + } + for (int i = 0; i < result.usePosList.size(); i++) { + assert result.usePosList.usePos(i) >= splitPos; + } + } + return result; + } + + /** + * Splits this interval at a specified position and returns + * the head as a new interval (this interval is the tail). + * + * Currently, only the first range can be split, and the new interval must not have split positions + */ + Interval splitFromStart(int splitPos, LinearScan allocator) { + assert operand.isVariable() : "cannot split fixed intervals"; + assert splitPos > from() && splitPos < to() : "can only split inside interval"; + assert splitPos > first.from && splitPos <= first.to : "can only split inside first range"; + assert firstUsage(RegisterPriority.None) > splitPos : "can not split when use positions are present"; + + // allocate new interval + Interval result = newSplitChild(allocator); + + // the new interval has only one range (checked by assertion above, + // so the splitting of the ranges is very simple + result.addRange(first.from, splitPos); + + if (splitPos == first.to) { + assert first.next != Range.EndMarker : "must not be at end"; + first = first.next; + } else { + first.from = splitPos; + } + + return result; + } + + // returns true if the opId is inside the interval + boolean covers(int opId, LIRInstruction.OperandMode mode) { + Range cur = first; + + while (cur != Range.EndMarker && cur.to < opId) { + cur = cur.next; + } + if (cur != Range.EndMarker) { + assert cur.to != cur.next.from : "ranges not separated"; + + if (mode == LIRInstruction.OperandMode.Output) { + return cur.from <= opId && opId < cur.to; + } else { + return cur.from <= opId && opId <= cur.to; + } + } + return false; + } + + // returns true if the interval has any hole between holeFrom and holeTo + // (even if the hole has only the length 1) + boolean hasHoleBetween(int holeFrom, int holeTo) { + assert holeFrom < holeTo : "check"; + assert from() <= holeFrom && holeTo <= to() : "index out of interval"; + + Range cur = first; + while (cur != Range.EndMarker) { + assert cur.to < cur.next.from : "no space between ranges"; + + // hole-range starts before this range . hole + if (holeFrom < cur.from) { + return true; + + // hole-range completely inside this range . no hole + } else { + if (holeTo <= cur.to) { + return false; + + // overlapping of hole-range with this range . hole + } else { + if (holeFrom <= cur.to) { + return true; + } + } + } + + cur = cur.next; + } + + return false; + } + + @Override + public String toString() { + String from = "?"; + String to = "?"; + if (first != null && first != Range.EndMarker) { + from = String.valueOf(from()); + to = String.valueOf(to()); + } + String location = this.location == null ? "" : "@" + this.location.name(); + return operandNumber + ":" + operand + (operand.isRegister() ? "" : location) + "[" + from + "," + to + "]"; + } + + /** + * Gets the use position information for this interval. + */ + public UsePosList usePosList() { + return usePosList; + } + + /** + * Gets a single line string for logging the details of this interval to a log stream. + * + * @param allocator the register allocator context + */ + public String logString(LinearScan allocator) { + StringBuilder buf = new StringBuilder(100); + buf.append(operandNumber).append(':').append(operand).append(' '); + if (!operand.isRegister()) { + if (location != null) { + buf.append("location{").append(location).append("} "); + } + } + + buf.append("hints{").append(splitParent.operandNumber); + Interval hint = locationHint(false, allocator); + if (hint != null && hint.operandNumber != splitParent.operandNumber) { + buf.append(", ").append(hint.operandNumber); + } + buf.append("} ranges{"); + + // print ranges + Range cur = first; + while (cur != Range.EndMarker) { + if (cur != first) { + buf.append(", "); + } + buf.append(cur); + cur = cur.next; + assert cur != null : "range list not closed with range sentinel"; + } + buf.append("} uses{"); + + // print use positions + int prev = 0; + for (int i = usePosList.size() - 1; i >= 0; --i) { + assert prev < usePosList.usePos(i) : "use positions not sorted"; + if (i != usePosList.size() - 1) { + buf.append(", "); + } + buf.append(usePosList.usePos(i)).append(':').append(usePosList.registerPriority(i)); + prev = usePosList.usePos(i); + } + return buf.append("} spill-state{").append(spillState()).append("}").toString(); + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/IntervalWalker.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/IntervalWalker.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,246 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.alloc; + +import com.oracle.max.graal.compiler.*; +import com.oracle.max.graal.compiler.alloc.Interval.*; +import com.oracle.max.graal.compiler.debug.*; + +/** + * + * @author Thomas Wuerthinger + */ +public class IntervalWalker { + + protected final C1XCompilation compilation; + protected final LinearScan allocator; + + /** + * Sorted list of intervals, not live before the current position. + */ + RegisterBindingLists unhandledLists; + + /** + * Sorted list of intervals, live at the current position. + */ + RegisterBindingLists activeLists; + + /** + * Sorted list of intervals in a life time hole at the current position. + */ + RegisterBindingLists inactiveLists; + + /** + * The current interval (taken from the unhandled list) being processed. + */ + protected Interval current; + + /** + * The current position (intercept point through the intervals). + */ + protected int currentPosition; + + /** + * The binding of the current interval being processed. + */ + protected RegisterBinding currentBinding; + + /** + * Processes the {@linkplain #current} interval in an attempt to allocate a physical + * register to it and thus allow it to be moved to a list of {@linkplain #activeLists active} intervals. + * + * @return {@code true} if a register was allocated to the {@linkplain #current} interval + */ + boolean activateCurrent() { + return true; + } + + void walkBefore(int lirOpId) { + walkTo(lirOpId - 1); + } + + void walk() { + walkTo(Integer.MAX_VALUE); + } + + /** + * Creates a new interval walker. + * + * @param allocator the register allocator context + * @param unhandledFixed the list of unhandled {@linkplain RegisterBinding#Fixed fixed} intervals + * @param unhandledAny the list of unhandled {@linkplain RegisterBinding#Any non-fixed} intervals + */ + IntervalWalker(LinearScan allocator, Interval unhandledFixed, Interval unhandledAny) { + this.compilation = allocator.compilation; + this.allocator = allocator; + + unhandledLists = new RegisterBindingLists(unhandledFixed, unhandledAny); + activeLists = new RegisterBindingLists(Interval.EndMarker, Interval.EndMarker); + inactiveLists = new RegisterBindingLists(Interval.EndMarker, Interval.EndMarker); + currentPosition = -1; + current = null; + nextInterval(); + } + + void removeFromList(Interval interval) { + if (interval.state == State.Active) { + activeLists.remove(RegisterBinding.Any, interval); + } else { + assert interval.state == State.Inactive : "invalid state"; + inactiveLists.remove(RegisterBinding.Any, interval); + } + } + + void walkTo(State state, int from) { + assert state == State.Active || state == State.Inactive : "wrong state"; + for (RegisterBinding binding : RegisterBinding.VALUES) { + Interval prevprev = null; + Interval prev = (state == State.Active) ? activeLists.get(binding) : inactiveLists.get(binding); + Interval next = prev; + while (next.currentFrom() <= from) { + Interval cur = next; + next = cur.next; + + boolean rangeHasChanged = false; + while (cur.currentTo() <= from) { + cur.nextRange(); + rangeHasChanged = true; + } + + // also handle move from inactive list to active list + rangeHasChanged = rangeHasChanged || (state == State.Inactive && cur.currentFrom() <= from); + + if (rangeHasChanged) { + // remove cur from list + if (prevprev == null) { + if (state == State.Active) { + activeLists.set(binding, next); + } else { + inactiveLists.set(binding, next); + } + } else { + prevprev.next = next; + } + prev = next; + if (cur.currentAtEnd()) { + // move to handled state (not maintained as a list) + cur.state = State.Handled; + intervalMoved(cur, binding, state, State.Handled); + } else if (cur.currentFrom() <= from) { + // sort into active list + activeLists.addToListSortedByCurrentFromPositions(binding, cur); + cur.state = State.Active; + if (prev == cur) { + assert state == State.Active : "check"; + prevprev = prev; + prev = cur.next; + } + intervalMoved(cur, binding, state, State.Active); + } else { + // sort into inactive list + inactiveLists.addToListSortedByCurrentFromPositions(binding, cur); + cur.state = State.Inactive; + if (prev == cur) { + assert state == State.Inactive : "check"; + prevprev = prev; + prev = cur.next; + } + intervalMoved(cur, binding, state, State.Inactive); + } + } else { + prevprev = prev; + prev = cur.next; + } + } + } + } + + void nextInterval() { + RegisterBinding binding; + Interval any = unhandledLists.any; + Interval fixed = unhandledLists.fixed; + + if (any != Interval.EndMarker) { + // intervals may start at same position . prefer fixed interval + binding = fixed != Interval.EndMarker && fixed.from() <= any.from() ? RegisterBinding.Fixed : RegisterBinding.Any; + + assert binding == RegisterBinding.Fixed && fixed.from() <= any.from() || binding == RegisterBinding.Any && any.from() <= fixed.from() : "wrong interval!!!"; + assert any == Interval.EndMarker || fixed == Interval.EndMarker || any.from() != fixed.from() || binding == RegisterBinding.Fixed : "if fixed and any-Interval start at same position, fixed must be processed first"; + + } else if (fixed != Interval.EndMarker) { + binding = RegisterBinding.Fixed; + } else { + current = null; + return; + } + currentBinding = binding; + current = unhandledLists.get(binding); + unhandledLists.set(binding, current.next); + current.next = Interval.EndMarker; + current.rewindRange(); + } + + void walkTo(int toOpId) { + assert currentPosition <= toOpId : "can not walk backwards"; + while (current != null) { + boolean isActive = current.from() <= toOpId; + int opId = isActive ? current.from() : toOpId; + + if (C1XOptions.TraceLinearScanLevel >= 2 && !TTY.isSuppressed()) { + if (currentPosition < opId) { + TTY.println(); + TTY.println("walkTo(%d) *", opId); + } + } + + // set currentPosition prior to call of walkTo + currentPosition = opId; + + // call walkTo even if currentPosition == id + walkTo(State.Active, opId); + walkTo(State.Inactive, opId); + + if (isActive) { + current.state = State.Active; + if (activateCurrent()) { + activeLists.addToListSortedByCurrentFromPositions(currentBinding, current); + intervalMoved(current, currentBinding, State.Unhandled, State.Active); + } + + nextInterval(); + } else { + return; + } + } + } + + private void intervalMoved(Interval interval, RegisterBinding kind, State from, State to) { + // intervalMoved() is called whenever an interval moves from one interval list to another. + // In the implementation of this method it is prohibited to move the interval to any list. + if (C1XOptions.TraceLinearScanLevel >= 4 && !TTY.isSuppressed()) { + TTY.print(from.toString() + " to " + to.toString()); + TTY.fillTo(23); + TTY.out().println(interval.logString(allocator)); + } + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/LIRInsertionBuffer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/LIRInsertionBuffer.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.alloc; + +import java.util.*; + +import com.oracle.max.graal.compiler.lir.*; +import com.oracle.max.graal.compiler.util.*; +import com.sun.cri.ci.*; + +/** + * + * @author Thomas Wuerthinger + */ +public final class LIRInsertionBuffer { + + private LIRList lir; // the lir list where ops of this buffer should be inserted later (null when uninitialized) + + // list of insertion points. index and count are stored alternately: + // indexAndCount[i * 2]: the index into lir list where "count" ops should be inserted + // indexAndCount[i * 2 + 1]: the number of ops to be inserted at index + private final IntList indexAndCount; + + // the LIROps to be inserted + private final List ops; + + private void appendNew(int index, int count) { + indexAndCount.add(index); + indexAndCount.add(count); + } + + private void setCountAt(int i, int value) { + indexAndCount.set((i << 1) + 1, value); + } + + LIRInsertionBuffer() { + ops = new ArrayList(8); + indexAndCount = new IntList(8); + } + + // must be called before using the insertion buffer + void init(LIRList lir) { + assert !initialized() : "already initialized"; + this.lir = lir; + indexAndCount.clear(); + ops.clear(); + } + + boolean initialized() { + return lir != null; + } + + // called automatically when the buffer is appended to the LIRList + public void finish() { + lir = null; + } + + // accessors + public LIRList lirList() { + return lir; + } + + public int numberOfInsertionPoints() { + return indexAndCount.size() >> 1; + } + + public int indexAt(int i) { + return indexAndCount.get((i << 1)); + } + + public int countAt(int i) { + return indexAndCount.get((i << 1) + 1); + } + + public int numberOfOps() { + return ops.size(); + } + + public LIRInstruction opAt(int i) { + return ops.get(i); + } + + void move(int index, CiValue src, CiValue dst, LIRDebugInfo info) { + append(index, new LIROp1(LIROpcode.Move, src, dst, dst.kind, info)); + } + + // Implementation of LIRInsertionBuffer + + private void append(int index, LIRInstruction op) { + assert indexAndCount.size() % 2 == 0 : "must have a count for each index"; + + int i = numberOfInsertionPoints() - 1; + if (i < 0 || indexAt(i) < index) { + appendNew(index, 1); + } else { + assert indexAt(i) == index : "can append LIROps in ascending order only"; + assert countAt(i) > 0 : "check"; + setCountAt(i, countAt(i) + 1); + } + ops.add(op); + + assert verify(); + } + + private boolean verify() { + int sum = 0; + int prevIdx = -1; + + for (int i = 0; i < numberOfInsertionPoints(); i++) { + assert prevIdx < indexAt(i) : "index must be ordered ascending"; + sum += countAt(i); + } + assert sum == numberOfOps() : "wrong total sum"; + return true; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/LinearScan.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/LinearScan.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,2317 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.alloc; + +import static com.sun.cri.ci.CiUtil.*; +import static java.lang.reflect.Modifier.*; + +import java.util.*; + +import com.oracle.max.graal.compiler.*; +import com.oracle.max.graal.compiler.alloc.Interval.*; +import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.compiler.gen.*; +import com.oracle.max.graal.compiler.graph.*; +import com.oracle.max.graal.compiler.ir.*; +import com.oracle.max.graal.compiler.lir.*; +import com.oracle.max.graal.compiler.lir.LIRInstruction.*; +import com.oracle.max.graal.compiler.observer.*; +import com.oracle.max.graal.compiler.util.*; +import com.oracle.max.graal.compiler.value.*; +import com.oracle.max.graal.compiler.value.FrameState.*; +import com.oracle.max.graal.graph.*; +import com.sun.cri.ci.*; +import com.sun.cri.ri.*; + +/** + * An implementation of the linear scan register allocator algorithm described + * in "Optimized Interval Splitting in a Linear Scan Register Allocator" + * by Christian Wimmer and Hanspeter Moessenboeck. + * + * @author Christian Wimmer (original HotSpot implementation) + * @author Thomas Wuerthinger + * @author Doug Simon + */ +public final class LinearScan { + + final C1XCompilation compilation; + final IR ir; + final LIRGenerator gen; + final FrameMap frameMap; + final RiRegisterAttributes[] registerAttributes; + final CiRegister[] registers; + + private static final int INITIAL_SPLIT_INTERVALS_CAPACITY = 32; + + /** + * List of blocks in linear-scan order. This is only correct as long as the CFG does not change. + */ + final LIRBlock[] sortedBlocks; + + final OperandPool operands; + + /** + * Number of stack slots used for intervals allocated to memory. + */ + int maxSpills; + + /** + * Unused spill slot for a single-word value because of alignment of a double-word value. + */ + CiStackSlot unusedSpillSlot; + + /** + * Map from {@linkplain #operandNumber(CiValue) operand numbers} to intervals. + */ + Interval[] intervals; + + /** + * The number of valid entries in {@link #intervals}. + */ + int intervalsSize; + + /** + * The index of the first entry in {@link #intervals} for a {@linkplain #createDerivedInterval(Interval) derived interval}. + */ + int firstDerivedIntervalIndex = -1; + + /** + * Intervals sorted by {@link Interval#from()}. + */ + Interval[] sortedIntervals; + + /** + * Map from an instruction {@linkplain LIRInstruction#id id} to the instruction. + * Entries should be retrieved with {@link #instructionForId(int)} as the id is + * not simply an index into this array. + */ + LIRInstruction[] opIdToInstructionMap; + + /** + * Map from an instruction {@linkplain LIRInstruction#id id} to the {@linkplain + * LIRBlock block} containing the instruction. Entries should be retrieved with + * {@link #blockForId(int)} as the id is not simply an index into this array. + */ + LIRBlock[] opIdToBlockMap; + + /** + * Bit set for each variable that is contained in each loop. + */ + BitMap2D intervalInLoop; + + public LinearScan(C1XCompilation compilation, IR ir, LIRGenerator gen, FrameMap frameMap) { + this.compilation = compilation; + this.ir = ir; + this.gen = gen; + this.frameMap = frameMap; + this.maxSpills = frameMap.initialSpillSlot(); + this.unusedSpillSlot = null; + this.sortedBlocks = ir.linearScanOrder().toArray(new LIRBlock[ir.linearScanOrder().size()]); + CiRegister[] allocatableRegisters = compilation.registerConfig.getAllocatableRegisters(); + this.registers = new CiRegister[CiRegister.maxRegisterNumber(allocatableRegisters) + 1]; + for (CiRegister reg : allocatableRegisters) { + registers[reg.number] = reg; + } + this.registerAttributes = compilation.registerConfig.getAttributesMap(); + this.operands = gen.operands; + } + + /** + * Converts an operand (variable or register) to an index in a flat address space covering all the + * {@linkplain CiVariable variables} and {@linkplain CiRegisterValue registers} being processed by this + * allocator. + */ + int operandNumber(CiValue operand) { + return operands.operandNumber(operand); + } + + static final IntervalPredicate IS_PRECOLORED_INTERVAL = new IntervalPredicate() { + @Override + public boolean apply(Interval i) { + return i.operand.isRegister(); + } + }; + + static final IntervalPredicate IS_VARIABLE_INTERVAL = new IntervalPredicate() { + @Override + public boolean apply(Interval i) { + return i.operand.isVariable(); + } + }; + + static final IntervalPredicate IS_OOP_INTERVAL = new IntervalPredicate() { + @Override + public boolean apply(Interval i) { + return !i.operand.isRegister() && i.kind() == CiKind.Object; + } + }; + + /** + * Gets an object describing the attributes of a given register according to this register configuration. + */ + RiRegisterAttributes attributes(CiRegister reg) { + return registerAttributes[reg.number]; + } + + /** + * Allocates the next available spill slot for a value of a given kind. + */ + CiStackSlot allocateSpillSlot(CiKind kind) { + CiStackSlot spillSlot; + if (numberOfSpillSlots(kind) == 2) { + if (isOdd(maxSpills)) { + // alignment of double-slot values + // the hole because of the alignment is filled with the next single-slot value + assert unusedSpillSlot == null : "wasting a spill slot"; + unusedSpillSlot = CiStackSlot.get(kind, maxSpills); + maxSpills++; + } + spillSlot = CiStackSlot.get(kind, maxSpills); + maxSpills += 2; + } else if (unusedSpillSlot != null) { + // re-use hole that was the result of a previous double-word alignment + spillSlot = unusedSpillSlot; + unusedSpillSlot = null; + } else { + spillSlot = CiStackSlot.get(kind, maxSpills); + maxSpills++; + } + + return spillSlot; + } + + void assignSpillSlot(Interval interval) { + // assign the canonical spill slot of the parent (if a part of the interval + // is already spilled) or allocate a new spill slot + if (interval.spillSlot() != null) { + interval.assignLocation(interval.spillSlot()); + } else { + CiStackSlot slot = allocateSpillSlot(interval.kind()); + interval.setSpillSlot(slot); + interval.assignLocation(slot); + } + } + + /** + * Creates a new interval. + * + * @param operand the operand for the interval + * @return the created interval + */ + Interval createInterval(CiValue operand) { + assert isProcessed(operand); + assert operand.isLegal(); + int operandNumber = operandNumber(operand); + Interval interval = new Interval(operand, operandNumber); + assert operandNumber < intervalsSize; + assert intervals[operandNumber] == null; + intervals[operandNumber] = interval; + return interval; + } + + /** + * Creates an interval as a result of splitting or spilling another interval. + * + * @param source an interval being split of spilled + * @return a new interval derived from {@code source} + */ + Interval createDerivedInterval(Interval source) { + if (firstDerivedIntervalIndex == -1) { + firstDerivedIntervalIndex = intervalsSize; + } + if (intervalsSize == intervals.length) { + intervals = Arrays.copyOf(intervals, intervals.length * 2); + } + intervalsSize++; + Interval interval = createInterval(operands.newVariable(source.kind())); + assert intervals[intervalsSize - 1] == interval; + return interval; + } + + // copy the variable flags if an interval is split + void copyRegisterFlags(Interval from, Interval to) { + if (operands.mustBeByteRegister(from.operand)) { + operands.setMustBeByteRegister((CiVariable) to.operand); + } + + // Note: do not copy the mustStartInMemory flag because it is not necessary for child + // intervals (only the very beginning of the interval must be in memory) + } + + // access to block list (sorted in linear scan order) + int blockCount() { + assert sortedBlocks.length == ir.linearScanOrder().size() : "invalid cached block list"; + return sortedBlocks.length; + } + + LIRBlock blockAt(int index) { + assert sortedBlocks[index] == ir.linearScanOrder().get(index) : "invalid cached block list"; + return sortedBlocks[index]; + } + + /** + * Gets the size of the {@link LIRBlock#liveIn} and {@link LIRBlock#liveOut} sets for a basic block. These sets do + * not include any operands allocated as a result of creating {@linkplain #createDerivedInterval(Interval) derived + * intervals}. + */ + int liveSetSize() { + return firstDerivedIntervalIndex == -1 ? operands.size() : firstDerivedIntervalIndex; + } + + int numLoops() { + return ir.numLoops(); + } + + boolean isIntervalInLoop(int interval, int loop) { + return intervalInLoop.at(interval, loop); + } + + Interval intervalFor(CiValue operand) { + int operandNumber = operandNumber(operand); + assert operandNumber < intervalsSize; + return intervals[operandNumber]; + } + + /** + * Gets the highest instruction id allocated by this object. + */ + int maxOpId() { + assert opIdToInstructionMap.length > 0 : "no operations"; + return (opIdToInstructionMap.length - 1) << 1; + } + + /** + * Converts an {@linkplain LIRInstruction#id instruction id} to an instruction index. + * All LIR instructions in a method have an index one greater than their linear-scan order predecesor + * with the first instruction having an index of 0. + */ + static int opIdToIndex(int opId) { + return opId >> 1; + } + + /** + * Retrieves the {@link LIRInstruction} based on its {@linkplain LIRInstruction#id id}. + * + * @param opId an instruction {@linkplain LIRInstruction#id id} + * @return the instruction whose {@linkplain LIRInstruction#id} {@code == id} + */ + LIRInstruction instructionForId(int opId) { + assert isEven(opId) : "opId not even"; + LIRInstruction instr = opIdToInstructionMap[opIdToIndex(opId)]; + assert instr.id == opId; + return instr; + } + + /** + * Gets the block containing a given instruction. + * + * @param opId an instruction {@linkplain LIRInstruction#id id} + * @return the block containing the instruction denoted by {@code opId} + */ + LIRBlock blockForId(int opId) { + assert opIdToBlockMap.length > 0 && opId >= 0 && opId <= maxOpId() + 1 : "opId out of range"; + return opIdToBlockMap[opIdToIndex(opId)]; + } + + boolean isBlockBegin(int opId) { + return opId == 0 || blockForId(opId) != blockForId(opId - 1); + } + + boolean coversBlockBegin(int opId1, int opId2) { + return blockForId(opId1) != blockForId(opId2); + } + + /** + * Determines if an {@link LIRInstruction} destroys all caller saved registers. + * + * @param opId an instruction {@linkplain LIRInstruction#id id} + * @return {@code true} if the instruction denoted by {@code id} destroys all caller saved registers. + */ + boolean hasCall(int opId) { + assert isEven(opId) : "opId not even"; + return instructionForId(opId).hasCall; + } + + /** + * Eliminates moves from register to stack if the stack slot is known to be correct. + */ + void changeSpillDefinitionPos(Interval interval, int defPos) { + assert interval.isSplitParent() : "can only be called for split parents"; + + switch (interval.spillState()) { + case NoDefinitionFound: + assert interval.spillDefinitionPos() == -1 : "must no be set before"; + interval.setSpillDefinitionPos(defPos); + interval.setSpillState(SpillState.NoSpillStore); + break; + + case NoSpillStore: + assert defPos <= interval.spillDefinitionPos() : "positions are processed in reverse order when intervals are created"; + if (defPos < interval.spillDefinitionPos() - 2 || instructionForId(interval.spillDefinitionPos()).code == LIROpcode.Xir) { + // second definition found, so no spill optimization possible for this interval + interval.setSpillState(SpillState.NoOptimization); + } else { + // two consecutive definitions (because of two-operand LIR form) + assert blockForId(defPos) == blockForId(interval.spillDefinitionPos()) : "block must be equal"; + } + break; + + case NoOptimization: + // nothing to do + break; + + default: + throw new CiBailout("other states not allowed at this time"); + } + } + + // called during register allocation + void changeSpillState(Interval interval, int spillPos) { + switch (interval.spillState()) { + case NoSpillStore: { + int defLoopDepth = blockForId(interval.spillDefinitionPos()).loopDepth(); + int spillLoopDepth = blockForId(spillPos).loopDepth(); + + if (defLoopDepth < spillLoopDepth) { + // the loop depth of the spilling position is higher then the loop depth + // at the definition of the interval . move write to memory out of loop + // by storing at definitin of the interval + interval.setSpillState(SpillState.StoreAtDefinition); + } else { + // the interval is currently spilled only once, so for now there is no + // reason to store the interval at the definition + interval.setSpillState(SpillState.OneSpillStore); + } + break; + } + + case OneSpillStore: { + // the interval is spilled more then once, so it is better to store it to + // memory at the definition + interval.setSpillState(SpillState.StoreAtDefinition); + break; + } + + case StoreAtDefinition: + case StartInMemory: + case NoOptimization: + case NoDefinitionFound: + // nothing to do + break; + + default: + throw new CiBailout("other states not allowed at this time"); + } + } + + abstract static class IntervalPredicate { + abstract boolean apply(Interval i); + } + + private static final IntervalPredicate mustStoreAtDefinition = new IntervalPredicate() { + @Override + public boolean apply(Interval i) { + return i.isSplitParent() && i.spillState() == SpillState.StoreAtDefinition; + } + }; + + // called once before assignment of register numbers + void eliminateSpillMoves() { + if (C1XOptions.TraceLinearScanLevel >= 3) { + TTY.println(" Eliminating unnecessary spill moves"); + } + + // collect all intervals that must be stored after their definition. + // the list is sorted by Interval.spillDefinitionPos + Interval interval; + interval = createUnhandledLists(mustStoreAtDefinition, null).first; + if (C1XOptions.DetailedAsserts) { + checkIntervals(interval); + } + + LIRInsertionBuffer insertionBuffer = new LIRInsertionBuffer(); + int numBlocks = blockCount(); + for (int i = 0; i < numBlocks; i++) { + LIRBlock block = blockAt(i); + List instructions = block.lir().instructionsList(); + int numInst = instructions.size(); + boolean hasNew = false; + + // iterate all instructions of the block. skip the first because it is always a label + for (int j = 1; j < numInst; j++) { + LIRInstruction op = instructions.get(j); + int opId = op.id; + + if (opId == -1) { + CiValue resultOperand = op.result(); + // remove move from register to stack if the stack slot is guaranteed to be correct. + // only moves that have been inserted by LinearScan can be removed. + assert op.code == LIROpcode.Move : "only moves can have a opId of -1"; + assert resultOperand.isVariable() : "LinearScan inserts only moves to variables"; + + LIROp1 op1 = (LIROp1) op; + Interval curInterval = intervalFor(resultOperand); + + if (!curInterval.location().isRegister() && curInterval.alwaysInMemory()) { + // move target is a stack slot that is always correct, so eliminate instruction + if (C1XOptions.TraceLinearScanLevel >= 4) { + TTY.println("eliminating move from interval %d to %d", operandNumber(op1.operand()), operandNumber(op1.result())); + } + instructions.set(j, null); // null-instructions are deleted by assignRegNum + } + + } else { + // insert move from register to stack just after the beginning of the interval + assert interval == Interval.EndMarker || interval.spillDefinitionPos() >= opId : "invalid order"; + assert interval == Interval.EndMarker || (interval.isSplitParent() && interval.spillState() == SpillState.StoreAtDefinition) : "invalid interval"; + + while (interval != Interval.EndMarker && interval.spillDefinitionPos() == opId) { + if (!hasNew) { + // prepare insertion buffer (appended when all instructions of the block are processed) + insertionBuffer.init(block.lir()); + hasNew = true; + } + + CiValue fromLocation = interval.location(); + CiValue toLocation = canonicalSpillOpr(interval); + + assert fromLocation.isRegister() : "from operand must be a register but is: " + fromLocation + " toLocation=" + toLocation + " spillState=" + interval.spillState(); + assert toLocation.isStackSlot() : "to operand must be a stack slot"; + + insertionBuffer.move(j, fromLocation, toLocation, null); + + if (C1XOptions.TraceLinearScanLevel >= 4) { + CiStackSlot slot = interval.spillSlot(); + TTY.println("inserting move after definition of interval %d to stack slot %d%s at opId %d", + interval.operandNumber, slot.index(), slot.inCallerFrame() ? " in caller frame" : "", opId); + } + + interval = interval.next; + } + } + } // end of instruction iteration + + if (hasNew) { + block.lir().append(insertionBuffer); + } + } // end of block iteration + + assert interval == Interval.EndMarker : "missed an interval"; + } + + private void checkIntervals(Interval interval) { + Interval prev = null; + Interval temp = interval; + while (temp != Interval.EndMarker) { + assert temp.spillDefinitionPos() > 0 : "invalid spill definition pos"; + if (prev != null) { + assert temp.from() >= prev.from() : "intervals not sorted"; + assert temp.spillDefinitionPos() >= prev.spillDefinitionPos() : "when intervals are sorted by from : then they must also be sorted by spillDefinitionPos"; + } + + assert temp.spillSlot() != null : "interval has no spill slot assigned"; + assert temp.spillDefinitionPos() >= temp.from() : "invalid order"; + assert temp.spillDefinitionPos() <= temp.from() + 2 : "only intervals defined once at their start-pos can be optimized"; + + if (C1XOptions.TraceLinearScanLevel >= 4) { + TTY.println("interval %d (from %d to %d) must be stored at %d", temp.operandNumber, temp.from(), temp.to(), temp.spillDefinitionPos()); + } + + prev = temp; + temp = temp.next; + } + } + + /** + * Numbers all instructions in all blocks. The numbering follows the {@linkplain ComputeLinearScanOrder linear scan order}. + */ + void numberInstructions() { + // Assign IDs to LIR nodes and build a mapping, lirOps, from ID to LIRInstruction node. + int numBlocks = blockCount(); + int numInstructions = 0; + for (int i = 0; i < numBlocks; i++) { + numInstructions += blockAt(i).lir().instructionsList().size(); + } + + // initialize with correct length + opIdToInstructionMap = new LIRInstruction[numInstructions]; + opIdToBlockMap = new LIRBlock[numInstructions]; + + int opId = 0; + int index = 0; + + for (int i = 0; i < numBlocks; i++) { + LIRBlock block = blockAt(i); + block.setFirstLirInstructionId(opId); + List instructions = block.lir().instructionsList(); + + int numInst = instructions.size(); + for (int j = 0; j < numInst; j++) { + LIRInstruction op = instructions.get(j); + op.id = opId; + + opIdToInstructionMap[index] = op; + opIdToBlockMap[index] = block; + assert instructionForId(opId) == op : "must match"; + + index++; + opId += 2; // numbering of lirOps by two + } + block.setLastLirInstructionId((opId - 2)); + } + assert index == numInstructions : "must match"; + assert (index << 1) == opId : "must match: " + (index << 1); + } + + /** + * Computes local live sets (i.e. {@link LIRBlock#liveGen} and {@link LIRBlock#liveKill}) separately for each block. + */ + void computeLocalLiveSets() { + int numBlocks = blockCount(); + int liveSize = liveSetSize(); + + BitMap2D localIntervalInLoop = new BitMap2D(operands.size(), numLoops()); + + // iterate all blocks + for (int i = 0; i < numBlocks; i++) { + LIRBlock block = blockAt(i); + final CiBitMap liveGen = new CiBitMap(liveSize); + final CiBitMap liveKill = new CiBitMap(liveSize); + + List instructions = block.lir().instructionsList(); + int numInst = instructions.size(); + + // iterate all instructions of the block. skip the first because it is always a label + assert !instructions.get(0).hasOperands() : "first operation must always be a label"; + for (int j = 1; j < numInst; j++) { + final LIRInstruction op = instructions.get(j); + + // iterate input operands of instruction + int n = op.operandCount(LIRInstruction.OperandMode.Input); + for (int k = 0; k < n; k++) { + CiValue operand = op.operandAt(LIRInstruction.OperandMode.Input, k); + + if (operand.isVariable()) { + int operandNum = operandNumber(operand); + if (!liveKill.get(operandNum)) { + liveGen.set(operandNum); + if (C1XOptions.TraceLinearScanLevel >= 4) { + TTY.println(" Setting liveGen for operand %d at instruction %d", operandNum, op.id); + } + } + if (block.loopIndex() >= 0) { + localIntervalInLoop.setBit(operandNum, block.loopIndex()); + } + } + + if (C1XOptions.DetailedAsserts) { + assert operand.isVariableOrRegister() : "visitor should only return register operands"; + verifyInput(block, liveKill, operand); + } + } + + // Add uses of live locals from interpreter's point of view for proper debug information generation + LIRDebugInfo info = op.info; + if (info != null) { + info.state.forEachLiveStateValue(new ValueProcedure() { + public void doValue(Value value) { + CiValue operand = value.operand(); + if (operand.isVariable()) { + int operandNum = operandNumber(operand); + if (!liveKill.get(operandNum)) { + liveGen.set(operandNum); + if (C1XOptions.TraceLinearScanLevel >= 4) { + TTY.println(" Setting liveGen for value %s, LIR opId %d, operand %d because of state for " + op.toString(), Util.valueString(value), op.id, operandNum); + } + } + } else if (operand.isRegister()) { + assert !isProcessed(operand) && !operand.kind.isObject(); + } else { + assert operand.isConstant() || operand.isIllegal() : "invalid operand for deoptimization value: " + value; + } + } + }); + } + + // iterate temp operands of instruction + n = op.operandCount(LIRInstruction.OperandMode.Temp); + for (int k = 0; k < n; k++) { + CiValue operand = op.operandAt(LIRInstruction.OperandMode.Temp, k); + + if (operand.isVariable()) { + int varNum = operandNumber(operand); + liveKill.set(varNum); + if (block.loopIndex() >= 0) { + localIntervalInLoop.setBit(varNum, block.loopIndex()); + } + } + + if (C1XOptions.DetailedAsserts) { + assert operand.isVariableOrRegister() : "visitor should only return register operands"; + verifyTemp(liveKill, operand); + } + } + + // iterate output operands of instruction + n = op.operandCount(LIRInstruction.OperandMode.Output); + for (int k = 0; k < n; k++) { + CiValue operand = op.operandAt(LIRInstruction.OperandMode.Output, k); + + if (operand.isVariable()) { + int varNum = operandNumber(operand); + liveKill.set(varNum); + if (block.loopIndex() >= 0) { + localIntervalInLoop.setBit(varNum, block.loopIndex()); + } + } + + if (C1XOptions.DetailedAsserts) { + assert operand.isVariableOrRegister() : "visitor should only return register operands"; + // fixed intervals are never live at block boundaries, so + // they need not be processed in live sets + // process them only in debug mode so that this can be checked + verifyTemp(liveKill, operand); + } + } + } // end of instruction iteration + + block.liveGen = liveGen; + block.liveKill = liveKill; + block.liveIn = new CiBitMap(liveSize); + block.liveOut = new CiBitMap(liveSize); + + if (C1XOptions.TraceLinearScanLevel >= 4) { + TTY.println("liveGen B%d %s", block.blockID(), block.liveGen); + TTY.println("liveKill B%d %s", block.blockID(), block.liveKill); + } + } // end of block iteration + + intervalInLoop = localIntervalInLoop; + } + + private void verifyTemp(CiBitMap liveKill, CiValue operand) { + // fixed intervals are never live at block boundaries, so + // they need not be processed in live sets + // process them only in debug mode so that this can be checked + if (!operand.isVariable()) { + if (isProcessed(operand)) { + liveKill.set(operandNumber(operand)); + } + } + } + + private void verifyInput(LIRBlock block, CiBitMap liveKill, CiValue operand) { + // fixed intervals are never live at block boundaries, so + // they need not be processed in live sets. + // this is checked by these assertions to be sure about it. + // the entry block may have incoming + // values in registers, which is ok. + if (!operand.isVariable() && block != ir.startBlock) { + if (isProcessed(operand)) { + assert liveKill.get(operandNumber(operand)) : "using fixed register that is not defined in this block"; + } + } + } + + /** + * Performs a backward dataflow analysis to compute global live sets (i.e. {@link LIRBlock#liveIn} and + * {@link LIRBlock#liveOut}) for each block. + */ + void computeGlobalLiveSets() { + int numBlocks = blockCount(); + boolean changeOccurred; + boolean changeOccurredInBlock; + int iterationCount = 0; + CiBitMap liveOut = new CiBitMap(liveSetSize()); // scratch set for calculations + + // Perform a backward dataflow analysis to compute liveOut and liveIn for each block. + // The loop is executed until a fixpoint is reached (no changes in an iteration) + do { + changeOccurred = false; + + // iterate all blocks in reverse order + for (int i = numBlocks - 1; i >= 0; i--) { + LIRBlock block = blockAt(i); + + changeOccurredInBlock = false; + + // liveOut(block) is the union of liveIn(sux), for successors sux of block + int n = block.numberOfSux(); + if (n > 0) { + // block has successors + if (n > 0) { + liveOut.setFrom(block.suxAt(0).liveIn); + for (int j = 1; j < n; j++) { + liveOut.setUnion(block.suxAt(j).liveIn); + } + } else { + liveOut.clearAll(); + } + + if (!block.liveOut.isSame(liveOut)) { + // A change occurred. Swap the old and new live out sets to avoid copying. + CiBitMap temp = block.liveOut; + block.liveOut = liveOut; + liveOut = temp; + + changeOccurred = true; + changeOccurredInBlock = true; + } + } + + if (iterationCount == 0 || changeOccurredInBlock) { + // liveIn(block) is the union of liveGen(block) with (liveOut(block) & !liveKill(block)) + // note: liveIn has to be computed only in first iteration or if liveOut has changed! + CiBitMap liveIn = block.liveIn; + liveIn.setFrom(block.liveOut); + liveIn.setDifference(block.liveKill); + liveIn.setUnion(block.liveGen); + } + + if (C1XOptions.TraceLinearScanLevel >= 4) { + traceLiveness(changeOccurredInBlock, iterationCount, block); + } + } + iterationCount++; + + if (changeOccurred && iterationCount > 50) { + throw new CiBailout("too many iterations in computeGlobalLiveSets"); + } + } while (changeOccurred); + + if (C1XOptions.DetailedAsserts) { + verifyLiveness(numBlocks); + } + + // check that the liveIn set of the first block is empty + LIRBlock startBlock = ir.startBlock; + CiBitMap liveInArgs = new CiBitMap(startBlock.liveIn.size()); + if (!startBlock.liveIn.isSame(liveInArgs)) { + if (C1XOptions.DetailedAsserts) { + reportFailure(numBlocks); + } + + TTY.println("preds=" + startBlock.blockPredecessors().size() + ", succs=" + startBlock.blockSuccessors().size()); + TTY.println("startBlock-ID: " + startBlock.blockID()); + + // bailout of if this occurs in product mode. + throw new CiBailout("liveIn set of first block must be empty"); + } + } + + private void reportFailure(int numBlocks) { + TTY.println(compilation.method.toString()); + TTY.println("Error: liveIn set of first block must be empty (when this fails, variables are used before they are defined)"); + TTY.print("affected registers:"); + TTY.println(ir.startBlock.liveIn.toString()); + + // print some additional information to simplify debugging + for (int operandNum = 0; operandNum < ir.startBlock.liveIn.size(); operandNum++) { + if (ir.startBlock.liveIn.get(operandNum)) { + CiValue operand = operands.operandFor(operandNum); + Value instr = operand.isVariable() ? gen.operands.instructionForResult(((CiVariable) operand)) : null; + TTY.println(" var %d (HIR instruction %s)", operandNum, instr == null ? " " : instr.toString()); + + if (instr instanceof Phi) { + Phi phi = (Phi) instr; + TTY.println("phi block begin: " + phi.block()); + TTY.println("pred count on blockbegin: " + phi.block().predecessors().size()); + TTY.println("phi values: " + phi.valueCount()); + TTY.println("phi block preds:"); + for (Node n : phi.block().predecessors()) { + TTY.println(n.toString()); + } + } + + for (int j = 0; j < numBlocks; j++) { + LIRBlock block = blockAt(j); + if (block.liveGen.get(operandNum)) { + TTY.println(" used in block B%d", block.blockID()); + for (LIRInstruction ins : block.lir().instructionsList()) { + TTY.println(ins.id + ": " + ins.result() + " " + ins.toString()); + } + } + if (block.liveKill.get(operandNum)) { + TTY.println(" defined in block B%d", block.blockID()); + for (LIRInstruction ins : block.lir().instructionsList()) { + TTY.println(ins.id + ": " + ins.result() + " " + ins.toString()); + } + } + } + } + } + } + + private void verifyLiveness(int numBlocks) { + // check that fixed intervals are not live at block boundaries + // (live set must be empty at fixed intervals) + for (int i = 0; i < numBlocks; i++) { + LIRBlock block = blockAt(i); + for (int j = 0; j <= operands.maxRegisterNumber(); j++) { + assert !block.liveIn.get(j) : "liveIn set of fixed register must be empty"; + assert !block.liveOut.get(j) : "liveOut set of fixed register must be empty"; + assert !block.liveGen.get(j) : "liveGen set of fixed register must be empty"; + } + } + } + + private void traceLiveness(boolean changeOccurredInBlock, int iterationCount, LIRBlock block) { + char c = iterationCount == 0 || changeOccurredInBlock ? '*' : ' '; + TTY.print("(%d) liveIn%c B%d ", iterationCount, c, block.blockID()); + TTY.println(block.liveIn.toString()); + TTY.print("(%d) liveOut%c B%d ", iterationCount, c, block.blockID()); + TTY.println(block.liveOut.toString()); + } + + Interval addUse(CiValue operand, int from, int to, RegisterPriority registerPriority, CiKind kind) { + if (!isProcessed(operand)) { + return null; + } + if (C1XOptions.TraceLinearScanLevel >= 2 && kind == null) { + TTY.println(" use %s from %d to %d (%s)", operand, from, to, registerPriority.name()); + } + + if (kind == null) { + kind = operand.kind.stackKind(); + } + Interval interval = intervalFor(operand); + if (interval == null) { + interval = createInterval(operand); + } + + if (kind != CiKind.Illegal) { + interval.setKind(kind); + } + + if (operand.isVariable() && gen.operands.mustStayInMemory((CiVariable) operand)) { + interval.addRange(from, maxOpId()); + } else { + interval.addRange(from, to); + } + + interval.addUsePos(to, registerPriority); + return interval; + } + + void addTemp(CiValue operand, int tempPos, RegisterPriority registerPriority, CiKind kind) { + if (!isProcessed(operand)) { + return; + } + Interval interval = intervalFor(operand); + if (interval == null) { + interval = createInterval(operand); + } + + if (kind != CiKind.Illegal) { + interval.setKind(kind); + } + + interval.addRange(tempPos, tempPos + 1); + interval.addUsePos(tempPos, registerPriority); + } + + boolean isProcessed(CiValue operand) { + return !operand.isRegister() || attributes(operand.asRegister()).isAllocatable; + } + + void addDef(CiValue operand, int defPos, RegisterPriority registerPriority, CiKind kind) { + if (!isProcessed(operand)) { + return; + } + if (C1XOptions.TraceLinearScanLevel >= 2) { + TTY.println(" def %s defPos %d (%s)", operand, defPos, registerPriority.name()); + } + Interval interval = intervalFor(operand); + if (interval != null) { + + if (kind != CiKind.Illegal) { + interval.setKind(kind); + } + + Range r = interval.first(); + if (r.from <= defPos) { + // Update the starting point (when a range is first created for a use, its + // start is the beginning of the current block until a def is encountered.) + r.from = defPos; + interval.addUsePos(defPos, registerPriority); + + } else { + // Dead value - make vacuous interval + // also add register priority for dead intervals + interval.addRange(defPos, defPos + 1); + interval.addUsePos(defPos, registerPriority); + if (C1XOptions.TraceLinearScanLevel >= 2) { + TTY.println("Warning: def of operand %s at %d occurs without use", operand, defPos); + } + } + + } else { + // Dead value - make vacuous interval + // also add register priority for dead intervals + interval = createInterval(operand); + if (kind != CiKind.Illegal) { + interval.setKind(kind); + } + + interval.addRange(defPos, defPos + 1); + interval.addUsePos(defPos, registerPriority); + if (C1XOptions.TraceLinearScanLevel >= 2) { + TTY.println("Warning: dead value %s at %d in live intervals", operand, defPos); + } + } + + changeSpillDefinitionPos(interval, defPos); + if (registerPriority == RegisterPriority.None && interval.spillState().ordinal() <= SpillState.StartInMemory.ordinal()) { + // detection of method-parameters and roundfp-results + // TODO: move this directly to position where use-kind is computed + interval.setSpillState(SpillState.StartInMemory); + } + } + + /** + * Determines the register priority for an instruction's output/result operand. + */ + RegisterPriority registerPriorityOfOutputOperand(LIRInstruction op, CiValue operand) { + if (op.code == LIROpcode.Move) { + LIROp1 move = (LIROp1) op; + CiValue res = move.result(); + boolean resultInMemory = res.isVariable() && operands.mustStartInMemory((CiVariable) res); + + if (resultInMemory) { + // Begin of an interval with mustStartInMemory set. + // This interval will always get a stack slot first, so return noUse. + return RegisterPriority.None; + + } else if (move.operand().isStackSlot()) { + // method argument (condition must be equal to handleMethodArguments) + return RegisterPriority.None; + + } + } + + if (operand.isVariable() && operands.mustStartInMemory((CiVariable) operand)) { + // result is a stack-slot, so prevent immediate reloading + return RegisterPriority.None; + } + + // all other operands require a register + return RegisterPriority.MustHaveRegister; + } + + /** + * Determines the priority which with an instruction's input operand will be allocated a register. + */ + RegisterPriority registerPriorityOfInputOperand(LIRInstruction op, CiValue operand) { + if (op.code == LIROpcode.Move) { + LIROp1 move = (LIROp1) op; + CiValue res = move.result(); + boolean resultInMemory = res.isVariable() && operands.mustStartInMemory((CiVariable) res); + + if (resultInMemory) { + // Move to an interval with mustStartInMemory set. + // To avoid moves from stack to stack (not allowed) force the input operand to a register + return RegisterPriority.MustHaveRegister; + + } else if (move.operand().isVariableOrRegister() && move.result().isVariableOrRegister()) { + // The input operand is not forced to a register (moves from stack to register are allowed), + // but it is faster if the input operand is in a register + return RegisterPriority.ShouldHaveRegister; + } + } + + if (compilation.target.arch.isX86()) { + if (op.code == LIROpcode.Cmove) { + // conditional moves can handle stack operands + assert op.result().isVariableOrRegister(); + return RegisterPriority.ShouldHaveRegister; + } + + // optimizations for second input operand of arithmetic operations on Intel + // this operand is allowed to be on the stack in some cases + CiKind kind = operand.kind.stackKind(); + if (kind == CiKind.Float || kind == CiKind.Double) { + // SSE float instruction (CiKind.Double only supported with SSE2) + switch (op.code) { + case Cmp: + case Add: + case Sub: + case Mul: + case Div: { + LIROp2 op2 = (LIROp2) op; + if (op2.operand1() != op2.operand2() && op2.operand2() == operand) { + assert (op2.result().isVariableOrRegister() || op.code == LIROpcode.Cmp) && op2.operand1().isVariableOrRegister() : "cannot mark second operand as stack if others are not in register"; + return RegisterPriority.ShouldHaveRegister; + } + } + } + } else if (kind != CiKind.Long) { + // integer instruction (note: long operands must always be in register) + switch (op.code) { + case Cmp: + case Add: + case Sub: + case LogicAnd: + case LogicOr: + case LogicXor: { + LIROp2 op2 = (LIROp2) op; + if (op2.operand1() != op2.operand2() && op2.operand2() == operand) { + assert (op2.result().isVariableOrRegister() || op.code == LIROpcode.Cmp) && op2.operand1().isVariableOrRegister() : "cannot mark second operand as stack if others are not in register"; + return RegisterPriority.ShouldHaveRegister; + } + } + } + } + } // X86 + + // all other operands require a register + return RegisterPriority.MustHaveRegister; + } + + /** + * Optimizes moves related to incoming stack based arguments. + * The interval for the destination of such moves is assigned + * the stack slot (which is in the caller's frame) as its + * spill slot. + */ + void handleMethodArguments(LIRInstruction op) { + if (op.code == LIROpcode.Move) { + LIROp1 move = (LIROp1) op; + + if (move.operand().isStackSlot()) { + CiStackSlot slot = (CiStackSlot) move.operand(); + if (C1XOptions.DetailedAsserts) { + int argSlots = compilation.method.signature().argumentSlots(!isStatic(compilation.method.accessFlags())); + assert slot.index() >= 0 && slot.index() < argSlots; + assert move.id > 0 : "invalid id"; + assert blockForId(move.id).numberOfPreds() == 0 : "move from stack must be in first block"; + assert move.result().isVariable() : "result of move must be a variable"; + + if (C1XOptions.TraceLinearScanLevel >= 4) { + TTY.println("found move from stack slot %s to %s", slot, move.result()); + } + } + + Interval interval = intervalFor(move.result()); + CiStackSlot copySlot = slot; + if (C1XOptions.CopyPointerStackArguments && slot.kind == CiKind.Object) { + copySlot = allocateSpillSlot(slot.kind); + } + interval.setSpillSlot(copySlot); + interval.assignLocation(copySlot); + } + } + } + + void addRegisterHints(LIRInstruction op) { + switch (op.code) { + case Move: // fall through + case Convert: { + LIROp1 move = (LIROp1) op; + + CiValue moveFrom = move.operand(); + CiValue moveTo = move.result(); + + if (moveTo.isVariableOrRegister() && moveFrom.isVariableOrRegister()) { + Interval from = intervalFor(moveFrom); + Interval to = intervalFor(moveTo); + if (from != null && to != null) { + to.setLocationHint(from); + if (C1XOptions.TraceLinearScanLevel >= 4) { + TTY.println("operation at opId %d: added hint from interval %d to %d", move.id, from.operandNumber, to.operandNumber); + } + } + } + break; + } + case Cmove: { + LIROp2 cmove = (LIROp2) op; + + CiValue moveFrom = cmove.operand1(); + CiValue moveTo = cmove.result(); + + if (moveTo.isVariableOrRegister() && moveFrom.isVariableOrRegister()) { + Interval from = intervalFor(moveFrom); + Interval to = intervalFor(moveTo); + if (from != null && to != null) { + to.setLocationHint(from); + if (C1XOptions.TraceLinearScanLevel >= 4) { + TTY.println("operation at opId %d: added hint from interval %d to %d", cmove.id, from.operandNumber, to.operandNumber); + } + } + } + break; + } + } + } + + void buildIntervals() { + intervalsSize = operands.size(); + intervals = new Interval[intervalsSize + INITIAL_SPLIT_INTERVALS_CAPACITY]; + + // create a list with all caller-save registers (cpu, fpu, xmm) + RiRegisterConfig registerConfig = compilation.registerConfig; + CiRegister[] callerSaveRegs = registerConfig.getCallerSaveRegisters(); + + // iterate all blocks in reverse order + for (int i = blockCount() - 1; i >= 0; i--) { + LIRBlock block = blockAt(i); + List instructions = block.lir().instructionsList(); + final int blockFrom = block.firstLirInstructionId(); + int blockTo = block.lastLirInstructionId(); + + assert blockFrom == instructions.get(0).id; + assert blockTo == instructions.get(instructions.size() - 1).id; + + // Update intervals for operands live at the end of this block; + CiBitMap live = block.liveOut; + for (int operandNum = live.nextSetBit(0); operandNum >= 0; operandNum = live.nextSetBit(operandNum + 1)) { + assert live.get(operandNum) : "should not stop here otherwise"; + CiValue operand = operands.operandFor(operandNum); + if (C1XOptions.TraceLinearScanLevel >= 2) { + TTY.println("live in %s to %d", operand, blockTo + 2); + } + + addUse(operand, blockFrom, blockTo + 2, RegisterPriority.None, CiKind.Illegal); + + // add special use positions for loop-end blocks when the + // interval is used anywhere inside this loop. It's possible + // that the block was part of a non-natural loop, so it might + // have an invalid loop index. + if (block.isLinearScanLoopEnd() && block.loopIndex() != -1 && isIntervalInLoop(operandNum, block.loopIndex())) { + intervalFor(operand).addUsePos(blockTo + 1, RegisterPriority.LiveAtLoopEnd); + } + } + + // iterate all instructions of the block in reverse order. + // skip the first instruction because it is always a label + // definitions of intervals are processed before uses + assert !instructions.get(0).hasOperands() : "first operation must always be a label"; + for (int j = instructions.size() - 1; j >= 1; j--) { + LIRInstruction op = instructions.get(j); + final int opId = op.id; + + // add a temp range for each register if operation destroys caller-save registers + if (op.hasCall) { + for (CiRegister r : callerSaveRegs) { + if (attributes(r).isAllocatable) { + addTemp(r.asValue(), opId, RegisterPriority.None, CiKind.Illegal); + } + } + if (C1XOptions.TraceLinearScanLevel >= 4) { + TTY.println("operation destroys all caller-save registers"); + } + } + + // Add any platform dependent temps + pdAddTemps(op); + + // visit definitions (output and temp operands) + int k; + int n; + n = op.operandCount(LIRInstruction.OperandMode.Output); + for (k = 0; k < n; k++) { + CiValue operand = op.operandAt(LIRInstruction.OperandMode.Output, k); + assert operand.isVariableOrRegister(); + addDef(operand, opId, registerPriorityOfOutputOperand(op, operand), operand.kind.stackKind()); + } + + n = op.operandCount(LIRInstruction.OperandMode.Temp); + for (k = 0; k < n; k++) { + CiValue operand = op.operandAt(LIRInstruction.OperandMode.Temp, k); + assert operand.isVariableOrRegister(); + if (C1XOptions.TraceLinearScanLevel >= 2) { + TTY.println(" temp %s tempPos %d (%s)", operand, opId, RegisterPriority.MustHaveRegister.name()); + } + addTemp(operand, opId, RegisterPriority.MustHaveRegister, operand.kind.stackKind()); + } + + // visit uses (input operands) + n = op.operandCount(LIRInstruction.OperandMode.Input); + for (k = 0; k < n; k++) { + CiValue operand = op.operandAt(LIRInstruction.OperandMode.Input, k); + assert operand.isVariableOrRegister(); + RegisterPriority p = registerPriorityOfInputOperand(op, operand); + Interval interval = addUse(operand, blockFrom, opId, p, null); + if (interval != null && op instanceof LIRXirInstruction) { + Range range = interval.first(); + // (tw) Increase range by 1 in order to overlap the input with the temp and the output operand. + if (range.to == opId) { + range.to++; + } + } + } + + // Add uses of live locals from interpreter's point of view for proper + // debug information generation + // Treat these operands as temp values (if the live range is extended + // to a call site, the value would be in a register at the call otherwise) + LIRDebugInfo info = op.info; + if (info != null) { + info.state.forEachLiveStateValue(new ValueProcedure() { + public void doValue(Value value) { + CiValue operand = value.operand(); + if (operand.isVariableOrRegister()) { + addUse(operand, blockFrom, (opId + 1), RegisterPriority.None, null); + } + } + }); + } + + // special steps for some instructions (especially moves) + handleMethodArguments(op); + addRegisterHints(op); + + } // end of instruction iteration + } // end of block iteration + + // add the range [0, 1] to all fixed intervals. + // the register allocator need not handle unhandled fixed intervals + for (Interval interval : intervals) { + if (interval != null && interval.operand.isRegister()) { + interval.addRange(0, 1); + } + } + } + + // * Phase 5: actual register allocation + + private void pdAddTemps(LIRInstruction op) { + // TODO Platform dependent! + assert compilation.target.arch.isX86(); + + switch (op.code) { + case Tan: + case Sin: + case Cos: { + // The slow path for these functions may need to save and + // restore all live registers but we don't want to save and + // restore everything all the time, so mark the xmms as being + // killed. If the slow path were explicit or we could propagate + // live register masks down to the assembly we could do better + // but we don't have any easy way to do that right now. We + // could also consider not killing all xmm registers if we + // assume that slow paths are uncommon but it's not clear that + // would be a good idea. + if (C1XOptions.TraceLinearScanLevel >= 2) { + TTY.println("killing XMMs for trig"); + } + int opId = op.id; + + for (CiRegister r : compilation.registerConfig.getCallerSaveRegisters()) { + if (r.isFpu()) { + addTemp(r.asValue(), opId, RegisterPriority.None, CiKind.Illegal); + } + } + break; + } + } + + } + + boolean isSorted(Interval[] intervals) { + int from = -1; + for (Interval interval : intervals) { + assert interval != null; + assert from <= interval.from(); + from = interval.from(); + + // XXX: very slow! + assert Arrays.asList(this.intervals).contains(interval); + } + return true; + } + + Interval addToList(Interval first, Interval prev, Interval interval) { + Interval newFirst = first; + if (prev != null) { + prev.next = interval; + } else { + newFirst = interval; + } + return newFirst; + } + + Interval.Pair createUnhandledLists(IntervalPredicate isList1, IntervalPredicate isList2) { + assert isSorted(sortedIntervals) : "interval list is not sorted"; + + Interval list1 = Interval.EndMarker; + Interval list2 = Interval.EndMarker; + + Interval list1Prev = null; + Interval list2Prev = null; + Interval v; + + int n = sortedIntervals.length; + for (int i = 0; i < n; i++) { + v = sortedIntervals[i]; + if (v == null) { + continue; + } + + if (isList1.apply(v)) { + list1 = addToList(list1, list1Prev, v); + list1Prev = v; + } else if (isList2 == null || isList2.apply(v)) { + list2 = addToList(list2, list2Prev, v); + list2Prev = v; + } + } + + if (list1Prev != null) { + list1Prev.next = Interval.EndMarker; + } + if (list2Prev != null) { + list2Prev.next = Interval.EndMarker; + } + + assert list1Prev == null || list1Prev.next == Interval.EndMarker : "linear list ends not with sentinel"; + assert list2Prev == null || list2Prev.next == Interval.EndMarker : "linear list ends not with sentinel"; + + return new Interval.Pair(list1, list2); + } + + void sortIntervalsBeforeAllocation() { + int sortedLen = 0; + for (Interval interval : intervals) { + if (interval != null) { + sortedLen++; + } + } + + Interval[] sortedList = new Interval[sortedLen]; + int sortedIdx = 0; + int sortedFromMax = -1; + + // special sorting algorithm: the original interval-list is almost sorted, + // only some intervals are swapped. So this is much faster than a complete QuickSort + for (Interval interval : intervals) { + if (interval != null) { + int from = interval.from(); + + if (sortedFromMax <= from) { + sortedList[sortedIdx++] = interval; + sortedFromMax = interval.from(); + } else { + // the assumption that the intervals are already sorted failed, + // so this interval must be sorted in manually + int j; + for (j = sortedIdx - 1; j >= 0 && from < sortedList[j].from(); j--) { + sortedList[j + 1] = sortedList[j]; + } + sortedList[j + 1] = interval; + sortedIdx++; + } + } + } + sortedIntervals = sortedList; + } + + void sortIntervalsAfterAllocation() { + if (firstDerivedIntervalIndex == -1) { + // no intervals have been added during allocation, so sorted list is already up to date + return; + } + + Interval[] oldList = sortedIntervals; + Interval[] newList = Arrays.copyOfRange(intervals, firstDerivedIntervalIndex, intervalsSize); + int oldLen = oldList.length; + int newLen = newList.length; + + // conventional sort-algorithm for new intervals + Arrays.sort(newList, INTERVAL_COMPARATOR); + + // merge old and new list (both already sorted) into one combined list + Interval[] combinedList = new Interval[oldLen + newLen]; + int oldIdx = 0; + int newIdx = 0; + + while (oldIdx + newIdx < combinedList.length) { + if (newIdx >= newLen || (oldIdx < oldLen && oldList[oldIdx].from() <= newList[newIdx].from())) { + combinedList[oldIdx + newIdx] = oldList[oldIdx]; + oldIdx++; + } else { + combinedList[oldIdx + newIdx] = newList[newIdx]; + newIdx++; + } + } + + sortedIntervals = combinedList; + } + + private static final Comparator INTERVAL_COMPARATOR = new Comparator() { + + public int compare(Interval a, Interval b) { + if (a != null) { + if (b != null) { + return a.from() - b.from(); + } else { + return -1; + } + } else { + if (b != null) { + return 1; + } else { + return 0; + } + } + } + }; + + public void allocateRegisters() { + Interval precoloredIntervals; + Interval notPrecoloredIntervals; + + Interval.Pair result = createUnhandledLists(IS_PRECOLORED_INTERVAL, IS_VARIABLE_INTERVAL); + precoloredIntervals = result.first; + notPrecoloredIntervals = result.second; + + // allocate cpu registers + LinearScanWalker lsw = new LinearScanWalker(this, precoloredIntervals, notPrecoloredIntervals); + lsw.walk(); + lsw.finishAllocation(); + } + + // * Phase 6: resolve data flow + // (insert moves at edges between blocks if intervals have been split) + + // wrapper for Interval.splitChildAtOpId that performs a bailout in product mode + // instead of returning null + Interval splitChildAtOpId(Interval interval, int opId, LIRInstruction.OperandMode mode) { + Interval result = interval.getSplitChildAtOpId(opId, mode, this); + + if (result != null) { + if (C1XOptions.TraceLinearScanLevel >= 4) { + TTY.println("Split child at pos " + opId + " of interval " + interval.toString() + " is " + result.toString()); + } + return result; + } + + throw new CiBailout("LinearScan: interval is null"); + } + + Interval intervalAtBlockBegin(LIRBlock block, CiValue operand) { + assert operand.isVariable() : "register number out of bounds"; + assert intervalFor(operand) != null : "no interval found"; + + return splitChildAtOpId(intervalFor(operand), block.firstLirInstructionId(), LIRInstruction.OperandMode.Output); + } + + Interval intervalAtBlockEnd(LIRBlock block, CiValue operand) { + assert operand.isVariable() : "register number out of bounds"; + assert intervalFor(operand) != null : "no interval found"; + + return splitChildAtOpId(intervalFor(operand), block.lastLirInstructionId() + 1, LIRInstruction.OperandMode.Output); + } + + Interval intervalAtOpId(CiValue operand, int opId) { + assert operand.isVariable() : "register number out of bounds"; + assert intervalFor(operand) != null : "no interval found"; + + return splitChildAtOpId(intervalFor(operand), opId, LIRInstruction.OperandMode.Input); + } + + void resolveCollectMappings(LIRBlock fromBlock, LIRBlock toBlock, MoveResolver moveResolver) { + assert moveResolver.checkEmpty(); + + int numOperands = operands.size(); + CiBitMap liveAtEdge = toBlock.liveIn; + + // visit all variables for which the liveAtEdge bit is set + for (int operandNum = liveAtEdge.nextSetBit(0); operandNum >= 0; operandNum = liveAtEdge.nextSetBit(operandNum + 1)) { + assert operandNum < numOperands : "live information set for not exisiting interval"; + assert fromBlock.liveOut.get(operandNum) && toBlock.liveIn.get(operandNum) : "interval not live at this edge"; + + CiValue liveOperand = operands.operandFor(operandNum); + Interval fromInterval = intervalAtBlockEnd(fromBlock, liveOperand); + Interval toInterval = intervalAtBlockBegin(toBlock, liveOperand); + + if (fromInterval != toInterval && (fromInterval.location() != toInterval.location())) { + // need to insert move instruction + moveResolver.addMapping(fromInterval, toInterval); + } + } + } + + void resolveFindInsertPos(LIRBlock fromBlock, LIRBlock toBlock, MoveResolver moveResolver) { + if (fromBlock.numberOfSux() <= 1) { + if (C1XOptions.TraceLinearScanLevel >= 4) { + TTY.println("inserting moves at end of fromBlock B%d", fromBlock.blockID()); + } + + List instructions = fromBlock.lir().instructionsList(); + LIRInstruction instr = instructions.get(instructions.size() - 1); + if (instr instanceof LIRBranch) { + LIRBranch branch = (LIRBranch) instr; + // insert moves before branch + assert branch.cond() == Condition.TRUE : "block does not end with an unconditional jump"; + moveResolver.setInsertPosition(fromBlock.lir(), instructions.size() - 2); + } else { + moveResolver.setInsertPosition(fromBlock.lir(), instructions.size() - 1); + } + + } else { + if (C1XOptions.TraceLinearScanLevel >= 4) { + TTY.println("inserting moves at beginning of toBlock B%d", toBlock.blockID()); + } + + if (C1XOptions.DetailedAsserts) { + assert fromBlock.lir().instructionsList().get(0) instanceof LIRLabel : "block does not start with a label"; + + // because the number of predecessor edges matches the number of + // successor edges, blocks which are reached by switch statements + // may have be more than one predecessor but it will be guaranteed + // that all predecessors will be the same. + for (int i = 0; i < toBlock.numberOfPreds(); i++) { + assert fromBlock == toBlock.predAt(i) : "all critical edges must be broken"; + } + } + + moveResolver.setInsertPosition(toBlock.lir(), 0); + } + } + + /** + * Inserts necessary moves (spilling or reloading) at edges between blocks for intervals that + * have been split. + */ + void resolveDataFlow() { + int numBlocks = blockCount(); + MoveResolver moveResolver = new MoveResolver(this); + CiBitMap blockCompleted = new CiBitMap(numBlocks); + CiBitMap alreadyResolved = new CiBitMap(numBlocks); + + int i; + for (i = 0; i < numBlocks; i++) { + LIRBlock block = blockAt(i); + + // check if block has only one predecessor and only one successor + if (block.numberOfPreds() == 1 && block.numberOfSux() == 1) { + List instructions = block.lir().instructionsList(); + assert instructions.get(0).code == LIROpcode.Label : "block must start with label"; + assert instructions.get(instructions.size() - 1).code == LIROpcode.Branch : "block with successors must end with branch (" + block + "), " + instructions.get(instructions.size() - 1); + assert ((LIRBranch) instructions.get(instructions.size() - 1)).cond() == Condition.TRUE : "block with successor must end with unconditional branch"; + + // check if block is empty (only label and branch) + if (instructions.size() == 2) { + LIRBlock pred = block.predAt(0); + LIRBlock sux = block.suxAt(0); + + // prevent optimization of two consecutive blocks + if (!blockCompleted.get(pred.linearScanNumber()) && !blockCompleted.get(sux.linearScanNumber())) { + if (C1XOptions.TraceLinearScanLevel >= 3) { + TTY.println(" optimizing empty block B%d (pred: B%d, sux: B%d)", block.blockID(), pred.blockID(), sux.blockID()); + } + blockCompleted.set(block.linearScanNumber()); + + // directly resolve between pred and sux (without looking at the empty block between) + resolveCollectMappings(pred, sux, moveResolver); + if (moveResolver.hasMappings()) { + moveResolver.setInsertPosition(block.lir(), 0); + moveResolver.resolveAndAppendMoves(); + } + } + } + } + } + + for (i = 0; i < numBlocks; i++) { + if (!blockCompleted.get(i)) { + LIRBlock fromBlock = blockAt(i); + alreadyResolved.setFrom(blockCompleted); + + int numSux = fromBlock.numberOfSux(); + for (int s = 0; s < numSux; s++) { + LIRBlock toBlock = fromBlock.suxAt(s); + + // check for duplicate edges between the same blocks (can happen with switch blocks) + if (!alreadyResolved.get(toBlock.linearScanNumber())) { + if (C1XOptions.TraceLinearScanLevel >= 3) { + TTY.println(" processing edge between B%d and B%d", fromBlock.blockID(), toBlock.blockID()); + } + alreadyResolved.set(toBlock.linearScanNumber()); + + // collect all intervals that have been split between fromBlock and toBlock + resolveCollectMappings(fromBlock, toBlock, moveResolver); + if (moveResolver.hasMappings()) { + resolveFindInsertPos(fromBlock, toBlock, moveResolver); + moveResolver.resolveAndAppendMoves(); + } + } + } + } + } + } + + // * Phase 7: assign register numbers back to LIR + // (includes computation of debug information and oop maps) + + boolean verifyAssignedLocation(Interval interval, CiValue location) { + CiKind kind = interval.kind(); + + assert location.isRegister() || location.isStackSlot(); + + if (location.isRegister()) { + CiRegister reg = location.asRegister(); + + // register + switch (kind) { + case Byte: + case Char: + case Short: + case Jsr: + case Word: + case Object: + case Int: { + assert reg.isCpu() : "not cpu register"; + break; + } + + case Long: { + assert reg.isCpu() : "not cpu register"; + break; + } + + case Float: { + assert !compilation.target.arch.isX86() || reg.isFpu() : "not xmm register: " + reg; + break; + } + + case Double: { + assert !compilation.target.arch.isX86() || reg.isFpu() : "not xmm register: " + reg; + break; + } + + default: { + throw Util.shouldNotReachHere(); + } + } + } + return true; + } + + CiStackSlot canonicalSpillOpr(Interval interval) { + assert interval.spillSlot() != null : "canonical spill slot not set"; + return interval.spillSlot(); + } + + /** + * Assigns the allocated location for an LIR instruction operand back into the instruction. + * + * @param operand an LIR instruction operand + * @param opId the id of the LIR instruction using {@code operand} + * @param mode the usage mode for {@code operand} by the instruction + * @return the location assigned for the operand + */ + private CiValue colorLirOperand(CiVariable operand, int opId, OperandMode mode) { + Interval interval = intervalFor(operand); + assert interval != null : "interval must exist"; + + if (opId != -1) { + if (C1XOptions.DetailedAsserts) { + LIRBlock block = blockForId(opId); + if (block.numberOfSux() <= 1 && opId == block.lastLirInstructionId()) { + // check if spill moves could have been appended at the end of this block, but + // before the branch instruction. So the split child information for this branch would + // be incorrect. + LIRInstruction instr = block.lir().instructionsList().get(block.lir().instructionsList().size() - 1); + if (instr instanceof LIRBranch) { + LIRBranch branch = (LIRBranch) instr; + if (block.liveOut.get(operandNumber(operand))) { + assert branch.cond() == Condition.TRUE : "block does not end with an unconditional jump"; + throw new CiBailout("can't get split child for the last branch of a block because the information would be incorrect (moves are inserted before the branch in resolveDataFlow)"); + } + } + } + } + + // operands are not changed when an interval is split during allocation, + // so search the right interval here + interval = splitChildAtOpId(interval, opId, mode); + } + + return interval.location(); + } + + IntervalWalker initComputeOopMaps() { + // setup lists of potential oops for walking + Interval oopIntervals; + Interval nonOopIntervals; + + oopIntervals = createUnhandledLists(IS_OOP_INTERVAL, null).first; + + // intervals that have no oops inside need not to be processed. + // to ensure a walking until the last instruction id, add a dummy interval + // with a high operation id + nonOopIntervals = new Interval(CiValue.IllegalValue, -1); + nonOopIntervals.addRange(Integer.MAX_VALUE - 2, Integer.MAX_VALUE - 1); + + return new IntervalWalker(this, oopIntervals, nonOopIntervals); + } + + void computeOopMap(IntervalWalker iw, LIRInstruction op, LIRDebugInfo info, boolean isCallSite, CiBitMap frameRefMap, CiBitMap regRefMap) { + if (C1XOptions.TraceLinearScanLevel >= 3) { + TTY.println("creating oop map at opId %d", op.id); + } + + // walk before the current operation . intervals that start at + // the operation (i.e. output operands of the operation) are not + // included in the oop map + iw.walkBefore(op.id); + + // Iterate through active intervals + for (Interval interval = iw.activeLists.get(RegisterBinding.Fixed); interval != Interval.EndMarker; interval = interval.next) { + CiValue operand = interval.operand; + + assert interval.currentFrom() <= op.id && op.id <= interval.currentTo() : "interval should not be active otherwise"; + assert interval.operand.isVariable() : "fixed interval found"; + + // Check if this range covers the instruction. Intervals that + // start or end at the current operation are not included in the + // oop map, except in the case of patching moves. For patching + // moves, any intervals which end at this instruction are included + // in the oop map since we may safepoint while doing the patch + // before we've consumed the inputs. + if (op.id < interval.currentTo()) { + // caller-save registers must not be included into oop-maps at calls + assert !isCallSite || !operand.isRegister() || !isCallerSave(operand) : "interval is in a caller-save register at a call . register will be overwritten"; + + CiValue location = interval.location(); + if (location.isStackSlot()) { + location = frameMap.toStackAddress((CiStackSlot) location); + } + info.setOop(location, compilation, frameRefMap, regRefMap); + + // Spill optimization: when the stack value is guaranteed to be always correct, + // then it must be added to the oop map even if the interval is currently in a register + if (interval.alwaysInMemory() && op.id > interval.spillDefinitionPos() && !interval.location().equals(interval.spillSlot())) { + assert interval.spillDefinitionPos() > 0 : "position not set correctly"; + assert interval.spillSlot() != null : "no spill slot assigned"; + assert !interval.operand.isRegister() : "interval is on stack : so stack slot is registered twice"; + info.setOop(frameMap.toStackAddress(interval.spillSlot()), compilation, frameRefMap, regRefMap); + } + } + } + } + + private boolean isCallerSave(CiValue operand) { + return attributes(operand.asRegister()).isCallerSave; + } + + void computeOopMap(IntervalWalker iw, LIRInstruction op, LIRDebugInfo info, CiBitMap frameRefMap, CiBitMap regRefMap) { + computeOopMap(iw, op, info, op.hasCall, frameRefMap, regRefMap); + if (op instanceof LIRCall) { + List pointerSlots = ((LIRCall) op).pointerSlots; + if (pointerSlots != null) { + for (CiValue v : pointerSlots) { + info.setOop(v, compilation, frameRefMap, regRefMap); + } + } + } else if (op instanceof LIRXirInstruction) { + List pointerSlots = ((LIRXirInstruction) op).pointerSlots; + if (pointerSlots != null) { + for (CiValue v : pointerSlots) { + info.setOop(v, compilation, frameRefMap, regRefMap); + } + } + } + } + + CiValue toCiValue(int opId, Value value) { + if (value != null && value.operand() != CiValue.IllegalValue) { + CiValue operand = value.operand(); + Constant con = null; + if (value instanceof Constant) { + con = (Constant) value; + } + + assert con == null || operand.isVariable() || operand.isConstant() || operand.isIllegal() : "Constant instructions have only constant operands (or illegal if constant is optimized away)"; + + if (operand.isVariable()) { + OperandMode mode = OperandMode.Input; + LIRBlock block = blockForId(opId); + if (block.numberOfSux() == 1 && opId == block.lastLirInstructionId()) { + // generating debug information for the last instruction of a block. + // if this instruction is a branch, spill moves are inserted before this branch + // and so the wrong operand would be returned (spill moves at block boundaries are not + // considered in the live ranges of intervals) + // Solution: use the first opId of the branch target block instead. + final LIRInstruction instr = block.lir().instructionsList().get(block.lir().instructionsList().size() - 1); + if (instr instanceof LIRBranch) { + if (block.liveOut.get(operandNumber(operand))) { + opId = block.suxAt(0).firstLirInstructionId(); + mode = OperandMode.Output; + } + } + } + + // Get current location of operand + // The operand must be live because debug information is considered when building the intervals + // if the interval is not live, colorLirOperand will cause an assert on failure + operand = colorLirOperand((CiVariable) operand, opId, mode); + assert !hasCall(opId) || operand.isStackSlot() || !isCallerSave(operand) : "cannot have caller-save register operands at calls"; + return operand; + } else if (operand.isRegister()) { + assert false : "must not reach here"; + return operand; + } else { + assert value instanceof Constant; + assert operand.isConstant() : "operand must be constant"; + return operand; + } + } else { + // return a dummy value because real value not needed + return CiValue.IllegalValue; + } + } + + CiFrame computeFrameForState(FrameState state, int opId, CiBitMap frameRefMap) { + CiValue[] values = new CiValue[state.valuesSize() + state.locksSize()]; + int valueIndex = 0; + + for (int i = 0; i < state.valuesSize(); i++) { + values[valueIndex++] = toCiValue(opId, state.valueAt(i)); + } + + for (int i = 0; i < state.locksSize(); i++) { + if (compilation.runtime.sizeOfBasicObjectLock() != 0) { + CiStackSlot monitorAddress = frameMap.toMonitorBaseStackAddress(i); + values[valueIndex++] = monitorAddress; + assert frameRefMap != null; + CiStackSlot objectAddress = frameMap.toMonitorObjectStackAddress(i); +// LIRDebugInfo.setBit(frameRefMap, objectAddress.index()); + frameRefMap.set(objectAddress.index()); + } else { + Value lock = state.lockAt(i); + if (lock.isConstant() && compilation.runtime.asJavaClass(lock.asConstant()) != null) { + // lock on class for synchronized static method + values[valueIndex++] = lock.asConstant(); + } else { + values[valueIndex++] = toCiValue(opId, lock); + } + } + } + CiFrame caller = null; + if (state.outerFrameState() != null) { + caller = computeFrameForState(state.outerFrameState(), opId, frameRefMap); + } + return new CiFrame(caller, state.method, state.bci, values, state.localsSize(), state.stackSize(), state.locksSize()); + } + + private void computeDebugInfo(IntervalWalker iw, LIRInstruction op) { + assert iw != null : "interval walker needed for debug information"; + computeDebugInfo(iw, op, op.info); + + if (op instanceof LIRXirInstruction) { + LIRXirInstruction xir = (LIRXirInstruction) op; + if (xir.infoAfter != null) { + computeDebugInfo(iw, op, xir.infoAfter); + } + } + } + + + private void computeDebugInfo(IntervalWalker iw, LIRInstruction op, LIRDebugInfo info) { + if (info != null) { + if (info.debugInfo == null) { + int frameSize = compilation.frameMap().frameSize(); + int frameWords = frameSize / compilation.target.spillSlotSize; + CiBitMap frameRefMap = new CiBitMap(frameWords); + CiBitMap regRefMap = !op.hasCall ? new CiBitMap(compilation.target.arch.registerReferenceMapBitCount) : null; + CiFrame frame = compilation.placeholderState != null ? null : computeFrame(info.state, op.id, frameRefMap); + computeOopMap(iw, op, info, frameRefMap, regRefMap); + info.debugInfo = new CiDebugInfo(frame, regRefMap, frameRefMap); + } else if (C1XOptions.DetailedAsserts) { + assert info.debugInfo.frame().equals(computeFrame(info.state, op.id, new CiBitMap(info.debugInfo.frameRefMap.size()))); + } + } + } + + CiFrame computeFrame(FrameState state, int opId, CiBitMap frameRefMap) { + if (C1XOptions.TraceLinearScanLevel >= 3) { + TTY.println("creating debug information at opId %d", opId); + } + return computeFrameForState(state, opId, frameRefMap); + } + + private void assignLocations(List instructions, IntervalWalker iw) { + int numInst = instructions.size(); + boolean hasDead = false; + + for (int j = 0; j < numInst; j++) { + LIRInstruction op = instructions.get(j); + if (op == null) { // this can happen when spill-moves are removed in eliminateSpillMoves + hasDead = true; + continue; + } + + // iterate all modes of the visitor and process all virtual operands + for (LIRInstruction.OperandMode mode : LIRInstruction.OPERAND_MODES) { + int n = op.operandCount(mode); + for (int k = 0; k < n; k++) { + CiValue operand = op.operandAt(mode, k); + if (operand.isVariable()) { + op.setOperandAt(mode, k, colorLirOperand((CiVariable) operand, op.id, mode)); + } + } + } + + if (op.info != null) { + // compute reference map and debug information + computeDebugInfo(iw, op); + } + + // make sure we haven't made the op invalid. + assert op.verify(); + + // remove useless moves + if (op.code == LIROpcode.Move) { + CiValue src = op.operand(0); + CiValue dst = op.result(); + if (dst == src || src.equals(dst)) { + // TODO: what about o.f = o.f and exceptions? + instructions.set(j, null); + hasDead = true; + } + } + } + + if (hasDead) { + // iterate all instructions of the block and remove all null-values. + int insertPoint = 0; + for (int j = 0; j < numInst; j++) { + LIRInstruction op = instructions.get(j); + if (op != null) { + if (insertPoint != j) { + instructions.set(insertPoint, op); + } + insertPoint++; + } + } + Util.truncate(instructions, insertPoint); + } + } + + private void assignLocations() { + IntervalWalker iw = initComputeOopMaps(); + for (LIRBlock block : sortedBlocks) { + assignLocations(block.lir().instructionsList(), iw); + } + } + + public void allocate() { + if (C1XOptions.PrintTimers) { + C1XTimers.LIFETIME_ANALYSIS.start(); + } + + numberInstructions(); + + printLir("Before register allocation", true); + + computeLocalLiveSets(); + computeGlobalLiveSets(); + + buildIntervals(); + sortIntervalsBeforeAllocation(); + + if (C1XOptions.PrintTimers) { + C1XTimers.LIFETIME_ANALYSIS.stop(); + C1XTimers.LINEAR_SCAN.start(); + } + + printIntervals("Before register allocation"); + + allocateRegisters(); + + if (C1XOptions.PrintTimers) { + C1XTimers.LINEAR_SCAN.stop(); + C1XTimers.RESOLUTION.start(); + } + + resolveDataFlow(); + + if (C1XOptions.PrintTimers) { + C1XTimers.RESOLUTION.stop(); + C1XTimers.DEBUG_INFO.start(); + } + + C1XMetrics.LSRASpills += (maxSpills - frameMap.initialSpillSlot()); + + // fill in number of spill slots into frameMap + frameMap.finalizeFrame(maxSpills); + + printIntervals("After register allocation"); + printLir("After register allocation", true); + + sortIntervalsAfterAllocation(); + + if (C1XOptions.DetailedAsserts) { + verify(); + } + + eliminateSpillMoves(); + assignLocations(); + + if (C1XOptions.DetailedAsserts) { + verifyIntervals(); + } + + if (C1XOptions.PrintTimers) { + C1XTimers.DEBUG_INFO.stop(); + C1XTimers.CODE_CREATE.start(); + } + + printLir("After register number assignment", true); + EdgeMoveOptimizer.optimize(ir.linearScanOrder()); + ControlFlowOptimizer.optimize(ir); + printLir("After control flow optimization", false); + } + + void printIntervals(String label) { + if (C1XOptions.TraceLinearScanLevel >= 1) { + int i; + TTY.println(); + TTY.println(label); + + for (Interval interval : intervals) { + if (interval != null) { + TTY.out().println(interval.logString(this)); + } + } + + TTY.println(); + TTY.println("--- Basic Blocks ---"); + for (i = 0; i < blockCount(); i++) { + LIRBlock block = blockAt(i); + TTY.print("B%d [%d, %d, %d, %d] ", block.blockID(), block.firstLirInstructionId(), block.lastLirInstructionId(), block.loopIndex(), block.loopDepth()); + } + TTY.println(); + TTY.println(); + } + + if (compilation.compiler.isObserved()) { + compilation.compiler.fireCompilationEvent(new CompilationEvent(compilation, label, this, intervals, intervalsSize)); + } + } + + void printLir(String label, boolean hirValid) { + if (C1XOptions.TraceLinearScanLevel >= 1 && !TTY.isSuppressed()) { + TTY.println(); + TTY.println(label); + LIRList.printLIR(ir.linearScanOrder()); + TTY.println(); + } + + if (compilation.compiler.isObserved()) { + compilation.compiler.fireCompilationEvent(new CompilationEvent(compilation, label, compilation.graph, hirValid, true)); + } + } + + boolean verify() { + // (check that all intervals have a correct register and that no registers are overwritten) + if (C1XOptions.TraceLinearScanLevel >= 2) { + TTY.println(" verifying intervals *"); + } + verifyIntervals(); + + if (C1XOptions.TraceLinearScanLevel >= 2) { + TTY.println(" verifying that no oops are in fixed intervals *"); + } + //verifyNoOopsInFixedIntervals(); + + if (C1XOptions.TraceLinearScanLevel >= 2) { + TTY.println(" verifying that unpinned constants are not alive across block boundaries"); + } + verifyConstants(); + + if (C1XOptions.TraceLinearScanLevel >= 2) { + TTY.println(" verifying register allocation *"); + } + verifyRegisters(); + + if (C1XOptions.TraceLinearScanLevel >= 2) { + TTY.println(" no errors found *"); + } + + return true; + } + + private void verifyRegisters() { + RegisterVerifier verifier = new RegisterVerifier(this); + verifier.verify(blockAt(0)); + } + + void verifyIntervals() { + int len = intervalsSize; + + for (int i = 0; i < len; i++) { + Interval i1 = intervals[i]; + if (i1 == null) { + continue; + } + + i1.checkSplitChildren(); + + if (i1.operandNumber != i) { + TTY.println("Interval %d is on position %d in list", i1.operandNumber, i); + TTY.println(i1.logString(this)); + throw new CiBailout(""); + } + + if (i1.operand.isVariable() && i1.kind() == CiKind.Illegal) { + TTY.println("Interval %d has no type assigned", i1.operandNumber); + TTY.println(i1.logString(this)); + throw new CiBailout(""); + } + + if (i1.location() == null) { + TTY.println("Interval %d has no register assigned", i1.operandNumber); + TTY.println(i1.logString(this)); + throw new CiBailout(""); + } + + if (!isProcessed(i1.location())) { + TTY.println("Can not have an Interval for an ignored register " + i1.location()); + TTY.println(i1.logString(this)); + throw new CiBailout(""); + } + + if (i1.first() == Range.EndMarker) { + TTY.println("Interval %d has no Range", i1.operandNumber); + TTY.println(i1.logString(this)); + throw new CiBailout(""); + } + + for (Range r = i1.first(); r != Range.EndMarker; r = r.next) { + if (r.from >= r.to) { + TTY.println("Interval %d has zero length range", i1.operandNumber); + TTY.println(i1.logString(this)); + throw new CiBailout(""); + } + } + + for (int j = i + 1; j < len; j++) { + Interval i2 = intervals[j]; + if (i2 == null) { + continue; + } + + // special intervals that are created in MoveResolver + // . ignore them because the range information has no meaning there + if (i1.from() == 1 && i1.to() == 2) { + continue; + } + if (i2.from() == 1 && i2.to() == 2) { + continue; + } + CiValue l1 = i1.location(); + CiValue l2 = i2.location(); + if (i1.intersects(i2) && (l1.equals(l2))) { + if (C1XOptions.DetailedAsserts) { + TTY.println("Intervals %d and %d overlap and have the same register assigned", i1.operandNumber, i2.operandNumber); + TTY.println(i1.logString(this)); + TTY.println(i2.logString(this)); + } + throw new CiBailout(""); + } + } + } + } + + void verifyNoOopsInFixedIntervals() { + Interval fixedIntervals; + Interval otherIntervals; + fixedIntervals = createUnhandledLists(IS_PRECOLORED_INTERVAL, null).first; + // to ensure a walking until the last instruction id, add a dummy interval + // with a high operation id + otherIntervals = new Interval(CiValue.IllegalValue, -1); + otherIntervals.addRange(Integer.MAX_VALUE - 2, Integer.MAX_VALUE - 1); + IntervalWalker iw = new IntervalWalker(this, fixedIntervals, otherIntervals); + + for (int i = 0; i < blockCount(); i++) { + LIRBlock block = blockAt(i); + + List instructions = block.lir().instructionsList(); + + for (int j = 0; j < instructions.size(); j++) { + LIRInstruction op = instructions.get(j); + + if (op.info != null) { + iw.walkBefore(op.id); + boolean checkLive = true; + + // Make sure none of the fixed registers is live across an + // oopmap since we can't handle that correctly. + if (checkLive) { + for (Interval interval = iw.activeLists.get(RegisterBinding.Fixed); interval != Interval.EndMarker; interval = interval.next) { + if (interval.currentTo() > op.id + 1) { + // This interval is live out of this op so make sure + // that this interval represents some value that's + // referenced by this op either as an input or output. + boolean ok = false; + for (LIRInstruction.OperandMode mode : LIRInstruction.OPERAND_MODES) { + int n = op.operandCount(mode); + for (int k = 0; k < n; k++) { + CiValue operand = op.operandAt(mode, k); + if (operand.isRegister()) { + if (intervalFor(operand) == interval) { + ok = true; + break; + } + } + } + } + assert ok : "fixed intervals should never be live across an oopmap point"; + } + } + } + } + } + } + } + + void verifyConstants() { + int numBlocks = blockCount(); + + for (int i = 0; i < numBlocks; i++) { + LIRBlock block = blockAt(i); + CiBitMap liveAtEdge = block.liveIn; + + // visit all operands where the liveAtEdge bit is set + for (int operandNum = liveAtEdge.nextSetBit(0); operandNum >= 0; operandNum = liveAtEdge.nextSetBit(operandNum + 1)) { + if (C1XOptions.TraceLinearScanLevel >= 4) { + TTY.println("checking interval %d of block B%d", operandNum, block.blockID()); + } + CiValue operand = operands.operandFor(operandNum); + assert operand.isVariable() : "value must have variable operand"; + Value value = gen.operands.instructionForResult(((CiVariable) operand)); + assert value != null : "all intervals live across block boundaries must have Value"; + // TKR assert value.asConstant() == null || value.isPinned() : + // "only pinned constants can be alive accross block boundaries"; + } + } + } + + public int numberOfSpillSlots(CiKind kind) { + return compilation.target.spillSlots(kind); + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/LinearScanWalker.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/LinearScanWalker.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,980 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.alloc; + +import static com.sun.cri.ci.CiUtil.*; + +import java.util.*; + +import com.oracle.max.graal.compiler.*; +import com.oracle.max.graal.compiler.alloc.Interval.*; +import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.compiler.lir.*; +import com.oracle.max.graal.compiler.util.*; +import com.sun.cri.ci.*; +import com.sun.cri.ci.CiRegister.*; + +/** + * + * @author Thomas Wuerthinger + */ +final class LinearScanWalker extends IntervalWalker { + + private CiRegister[] availableRegs; + + private final int[] usePos; + private final int[] blockPos; + + private List[] spillIntervals; + + private MoveResolver moveResolver; // for ordering spill moves + + // accessors mapped to same functions in class LinearScan + int blockCount() { + return allocator.blockCount(); + } + + LIRBlock blockAt(int idx) { + return allocator.blockAt(idx); + } + + LIRBlock blockOfOpWithId(int opId) { + return allocator.blockForId(opId); + } + + LinearScanWalker(LinearScan allocator, Interval unhandledFixedFirst, Interval unhandledAnyFirst) { + super(allocator, unhandledFixedFirst, unhandledAnyFirst); + moveResolver = new MoveResolver(allocator); + spillIntervals = Util.uncheckedCast(new List[allocator.registers.length]); + for (int i = 0; i < allocator.registers.length; i++) { + spillIntervals[i] = new ArrayList(2); + } + usePos = new int[allocator.registers.length]; + blockPos = new int[allocator.registers.length]; + } + + void initUseLists(boolean onlyProcessUsePos) { + for (CiRegister register : availableRegs) { + int i = register.number; + usePos[i] = Integer.MAX_VALUE; + + if (!onlyProcessUsePos) { + blockPos[i] = Integer.MAX_VALUE; + spillIntervals[i].clear(); + } + } + } + + void excludeFromUse(Interval i) { + CiValue location = i.location(); + int i1 = location.asRegister().number; + if (i1 >= availableRegs[0].number && i1 <= availableRegs[availableRegs.length - 1].number) { + usePos[i1] = 0; + } + } + + void setUsePos(Interval interval, int usePos, boolean onlyProcessUsePos) { + if (usePos != -1) { + assert usePos != 0 : "must use excludeFromUse to set usePos to 0"; + int i = interval.location().asRegister().number; + if (i >= availableRegs[0].number && i <= availableRegs[availableRegs.length - 1].number) { + if (this.usePos[i] > usePos) { + this.usePos[i] = usePos; + } + if (!onlyProcessUsePos) { + spillIntervals[i].add(interval); + } + } + } + } + + void setBlockPos(Interval i, int blockPos) { + if (blockPos != -1) { + int reg = i.location().asRegister().number; + if (reg >= availableRegs[0].number && reg <= availableRegs[availableRegs.length - 1].number) { + if (this.blockPos[reg] > blockPos) { + this.blockPos[reg] = blockPos; + } + if (usePos[reg] > blockPos) { + usePos[reg] = blockPos; + } + } + } + } + + void freeExcludeActiveFixed() { + Interval interval = activeLists.get(RegisterBinding.Fixed); + while (interval != Interval.EndMarker) { + assert interval.location().isRegister() : "active interval must have a register assigned"; + excludeFromUse(interval); + interval = interval.next; + } + } + + void freeExcludeActiveAny() { + Interval interval = activeLists.get(RegisterBinding.Any); + while (interval != Interval.EndMarker) { + assert interval.location().isRegister() : "active interval must have a register assigned"; + excludeFromUse(interval); + interval = interval.next; + } + } + + void freeCollectInactiveFixed(Interval current) { + Interval interval = inactiveLists.get(RegisterBinding.Fixed); + while (interval != Interval.EndMarker) { + if (current.to() <= interval.currentFrom()) { + assert interval.currentIntersectsAt(current) == -1 : "must not intersect"; + setUsePos(interval, interval.currentFrom(), true); + } else { + setUsePos(interval, interval.currentIntersectsAt(current), true); + } + interval = interval.next; + } + } + + void freeCollectInactiveAny(Interval current) { + Interval interval = inactiveLists.get(RegisterBinding.Any); + while (interval != Interval.EndMarker) { + setUsePos(interval, interval.currentIntersectsAt(current), true); + interval = interval.next; + } + } + + void freeCollectUnhandled(RegisterBinding kind, Interval current) { + Interval interval = unhandledLists.get(kind); + while (interval != Interval.EndMarker) { + setUsePos(interval, interval.intersectsAt(current), true); + if (kind == RegisterBinding.Fixed && current.to() <= interval.from()) { + setUsePos(interval, interval.from(), true); + } + interval = interval.next; + } + } + + void spillExcludeActiveFixed() { + Interval interval = activeLists.get(RegisterBinding.Fixed); + while (interval != Interval.EndMarker) { + excludeFromUse(interval); + interval = interval.next; + } + } + + void spillBlockUnhandledFixed(Interval current) { + Interval interval = unhandledLists.get(RegisterBinding.Fixed); + while (interval != Interval.EndMarker) { + setBlockPos(interval, interval.intersectsAt(current)); + interval = interval.next; + } + } + + void spillBlockInactiveFixed(Interval current) { + Interval interval = inactiveLists.get(RegisterBinding.Fixed); + while (interval != Interval.EndMarker) { + if (current.to() > interval.currentFrom()) { + setBlockPos(interval, interval.currentIntersectsAt(current)); + } else { + assert interval.currentIntersectsAt(current) == -1 : "invalid optimization: intervals intersect"; + } + + interval = interval.next; + } + } + + void spillCollectActiveAny() { + Interval interval = activeLists.get(RegisterBinding.Any); + while (interval != Interval.EndMarker) { + setUsePos(interval, Math.min(interval.nextUsage(RegisterPriority.LiveAtLoopEnd, currentPosition), interval.to()), false); + interval = interval.next; + } + } + + void spillCollectInactiveAny(Interval current) { + Interval interval = inactiveLists.get(RegisterBinding.Any); + while (interval != Interval.EndMarker) { + if (interval.currentIntersects(current)) { + setUsePos(interval, Math.min(interval.nextUsage(RegisterPriority.LiveAtLoopEnd, currentPosition), interval.to()), false); + } + interval = interval.next; + } + } + + void insertMove(int opId, Interval srcIt, Interval dstIt) { + // output all moves here. When source and target are equal, the move is + // optimized away later in assignRegNums + + opId = (opId + 1) & ~1; + LIRBlock opBlock = allocator.blockForId(opId); + assert opId > 0 && allocator.blockForId(opId - 2) == opBlock : "cannot insert move at block boundary"; + + // calculate index of instruction inside instruction list of current block + // the minimal index (for a block with no spill moves) can be calculated because the + // numbering of instructions is known. + // When the block already contains spill moves, the index must be increased until the + // correct index is reached. + List list = opBlock.lir().instructionsList(); + int index = (opId - list.get(0).id) >> 1; + assert list.get(index).id <= opId : "error in calculation"; + + while (list.get(index).id != opId) { + index++; + assert 0 <= index && index < list.size() : "index out of bounds"; + } + assert 1 <= index && index < list.size() : "index out of bounds"; + assert list.get(index).id == opId : "error in calculation"; + + // insert new instruction before instruction at position index + moveResolver.moveInsertPosition(opBlock.lir(), index - 1); + moveResolver.addMapping(srcIt, dstIt); + } + + int findOptimalSplitPos(LIRBlock minBlock, LIRBlock maxBlock, int maxSplitPos) { + int fromBlockNr = minBlock.linearScanNumber(); + int toBlockNr = maxBlock.linearScanNumber(); + + assert 0 <= fromBlockNr && fromBlockNr < blockCount() : "out of range"; + assert 0 <= toBlockNr && toBlockNr < blockCount() : "out of range"; + assert fromBlockNr < toBlockNr : "must cross block boundary"; + + // Try to split at end of maxBlock. If this would be after + // maxSplitPos, then use the begin of maxBlock + int optimalSplitPos = maxBlock.lastLirInstructionId() + 2; + if (optimalSplitPos > maxSplitPos) { + optimalSplitPos = maxBlock.firstLirInstructionId(); + } + + int minLoopDepth = maxBlock.loopDepth(); + for (int i = toBlockNr - 1; i >= fromBlockNr; i--) { + LIRBlock cur = blockAt(i); + + if (cur.loopDepth() < minLoopDepth) { + // block with lower loop-depth found . split at the end of this block + minLoopDepth = cur.loopDepth(); + optimalSplitPos = cur.lastLirInstructionId() + 2; + } + } + assert optimalSplitPos > allocator.maxOpId() || allocator.isBlockBegin(optimalSplitPos) : "algorithm must move split pos to block boundary"; + + return optimalSplitPos; + } + + int findOptimalSplitPos(Interval interval, int minSplitPos, int maxSplitPos, boolean doLoopOptimization) { + int optimalSplitPos = -1; + if (minSplitPos == maxSplitPos) { + // trivial case, no optimization of split position possible + if (C1XOptions.TraceLinearScanLevel >= 4) { + TTY.println(" min-pos and max-pos are equal, no optimization possible"); + } + optimalSplitPos = minSplitPos; + + } else { + assert minSplitPos < maxSplitPos : "must be true then"; + assert minSplitPos > 0 : "cannot access minSplitPos - 1 otherwise"; + + // reason for using minSplitPos - 1: when the minimal split pos is exactly at the + // beginning of a block, then minSplitPos is also a possible split position. + // Use the block before as minBlock, because then minBlock.lastLirInstructionId() + 2 == minSplitPos + LIRBlock minBlock = allocator.blockForId(minSplitPos - 1); + + // reason for using maxSplitPos - 1: otherwise there would be an assert on failure + // when an interval ends at the end of the last block of the method + // (in this case, maxSplitPos == allocator().maxLirOpId() + 2, and there is no + // block at this opId) + LIRBlock maxBlock = allocator.blockForId(maxSplitPos - 1); + + assert minBlock.linearScanNumber() <= maxBlock.linearScanNumber() : "invalid order"; + if (minBlock == maxBlock) { + // split position cannot be moved to block boundary : so split as late as possible + if (C1XOptions.TraceLinearScanLevel >= 4) { + TTY.println(" cannot move split pos to block boundary because minPos and maxPos are in same block"); + } + optimalSplitPos = maxSplitPos; + + } else { + if (interval.hasHoleBetween(maxSplitPos - 1, maxSplitPos) && !allocator.isBlockBegin(maxSplitPos)) { + // Do not move split position if the interval has a hole before maxSplitPos. + // Intervals resulting from Phi-Functions have more than one definition (marked + // as mustHaveRegister) with a hole before each definition. When the register is needed + // for the second definition : an earlier reloading is unnecessary. + if (C1XOptions.TraceLinearScanLevel >= 4) { + TTY.println(" interval has hole just before maxSplitPos, so splitting at maxSplitPos"); + } + optimalSplitPos = maxSplitPos; + + } else { + // seach optimal block boundary between minSplitPos and maxSplitPos + if (C1XOptions.TraceLinearScanLevel >= 4) { + TTY.println(" moving split pos to optimal block boundary between block B%d and B%d", minBlock.blockID(), maxBlock.blockID()); + } + + if (doLoopOptimization) { + // Loop optimization: if a loop-end marker is found between min- and max-position : + // then split before this loop + int loopEndPos = interval.nextUsageExact(RegisterPriority.LiveAtLoopEnd, minBlock.lastLirInstructionId() + 2); + if (C1XOptions.TraceLinearScanLevel >= 4) { + TTY.println(" loop optimization: loop end found at pos %d", loopEndPos); + } + + assert loopEndPos > minSplitPos : "invalid order"; + if (loopEndPos < maxSplitPos) { + // loop-end marker found between min- and max-position + // if it is not the end marker for the same loop as the min-position : then move + // the max-position to this loop block. + // Desired result: uses tagged as shouldHaveRegister inside a loop cause a reloading + // of the interval (normally, only mustHaveRegister causes a reloading) + LIRBlock loopBlock = allocator.blockForId(loopEndPos); + + if (C1XOptions.TraceLinearScanLevel >= 4) { + TTY.println(" interval is used in loop that ends in block B%d, so trying to move maxBlock back from B%d to B%d", loopBlock.blockID(), maxBlock.blockID(), loopBlock.blockID()); + } + assert loopBlock != minBlock : "loopBlock and minBlock must be different because block boundary is needed between"; + + optimalSplitPos = findOptimalSplitPos(minBlock, loopBlock, loopBlock.lastLirInstructionId() + 2); + if (optimalSplitPos == loopBlock.lastLirInstructionId() + 2) { + optimalSplitPos = -1; + if (C1XOptions.TraceLinearScanLevel >= 4) { + TTY.println(" loop optimization not necessary"); + } + } else { + if (C1XOptions.TraceLinearScanLevel >= 4) { + TTY.println(" loop optimization successful"); + } + } + } + } + + if (optimalSplitPos == -1) { + // not calculated by loop optimization + optimalSplitPos = findOptimalSplitPos(minBlock, maxBlock, maxSplitPos); + } + } + } + } + if (C1XOptions.TraceLinearScanLevel >= 4) { + TTY.println(" optimal split position: %d", optimalSplitPos); + } + + return optimalSplitPos; + } + + // split an interval at the optimal position between minSplitPos and + // maxSplitPos in two parts: + // 1) the left part has already a location assigned + // 2) the right part is sorted into to the unhandled-list + void splitBeforeUsage(Interval interval, int minSplitPos, int maxSplitPos) { + if (C1XOptions.TraceLinearScanLevel >= 2) { + TTY.println("----- splitting interval: "); + } + if (C1XOptions.TraceLinearScanLevel >= 4) { + TTY.println(interval.logString(allocator)); + } + if (C1XOptions.TraceLinearScanLevel >= 2) { + TTY.println(" between %d and %d", minSplitPos, maxSplitPos); + } + + assert interval.from() < minSplitPos : "cannot split at start of interval"; + assert currentPosition < minSplitPos : "cannot split before current position"; + assert minSplitPos <= maxSplitPos : "invalid order"; + assert maxSplitPos <= interval.to() : "cannot split after end of interval"; + + int optimalSplitPos = findOptimalSplitPos(interval, minSplitPos, maxSplitPos, true); + + assert minSplitPos <= optimalSplitPos && optimalSplitPos <= maxSplitPos : "out of range"; + assert optimalSplitPos <= interval.to() : "cannot split after end of interval"; + assert optimalSplitPos > interval.from() : "cannot split at start of interval"; + + if (optimalSplitPos == interval.to() && interval.nextUsage(RegisterPriority.MustHaveRegister, minSplitPos) == Integer.MAX_VALUE) { + // the split position would be just before the end of the interval + // . no split at all necessary + if (C1XOptions.TraceLinearScanLevel >= 4) { + TTY.println(" no split necessary because optimal split position is at end of interval"); + } + return; + } + + // must calculate this before the actual split is performed and before split position is moved to odd opId + boolean moveNecessary = !allocator.isBlockBegin(optimalSplitPos) && !interval.hasHoleBetween(optimalSplitPos - 1, optimalSplitPos); + + if (!allocator.isBlockBegin(optimalSplitPos)) { + // move position before actual instruction (odd opId) + optimalSplitPos = (optimalSplitPos - 1) | 1; + } + + if (C1XOptions.TraceLinearScanLevel >= 4) { + TTY.println(" splitting at position %d", optimalSplitPos); + } + assert allocator.isBlockBegin(optimalSplitPos) || (optimalSplitPos % 2 == 1) : "split pos must be odd when not on block boundary"; + assert !allocator.isBlockBegin(optimalSplitPos) || (optimalSplitPos % 2 == 0) : "split pos must be even on block boundary"; + + Interval splitPart = interval.split(optimalSplitPos, allocator); + + allocator.copyRegisterFlags(interval, splitPart); + splitPart.setInsertMoveWhenActivated(moveNecessary); + + assert splitPart.from() >= current.currentFrom() : "cannot append new interval before current walk position"; + unhandledLists.addToListSortedByStartAndUsePositions(RegisterBinding.Any, splitPart); + + if (C1XOptions.TraceLinearScanLevel >= 2) { + TTY.println(" split interval in two parts (insertMoveWhenActivated: %b)", moveNecessary); + } + if (C1XOptions.TraceLinearScanLevel >= 2) { + TTY.print(" "); + TTY.println(interval.logString(allocator)); + TTY.print(" "); + TTY.println(splitPart.logString(allocator)); + } + } + +// split an interval at the optimal position between minSplitPos and +// maxSplitPos in two parts: +// 1) the left part has already a location assigned +// 2) the right part is always on the stack and therefore ignored in further processing + + void splitForSpilling(Interval interval) { + // calculate allowed range of splitting position + int maxSplitPos = currentPosition; + int minSplitPos = Math.max(interval.previousUsage(RegisterPriority.ShouldHaveRegister, maxSplitPos) + 1, interval.from()); + + if (C1XOptions.TraceLinearScanLevel >= 2) { + TTY.print("----- splitting and spilling interval: "); + TTY.println(interval.logString(allocator)); + TTY.println(" between %d and %d", minSplitPos, maxSplitPos); + } + + assert interval.state == State.Active : "why spill interval that is not active?"; + assert interval.from() <= minSplitPos : "cannot split before start of interval"; + assert minSplitPos <= maxSplitPos : "invalid order"; + assert maxSplitPos < interval.to() : "cannot split at end end of interval"; + assert currentPosition < interval.to() : "interval must not end before current position"; + + if (minSplitPos == interval.from()) { + // the whole interval is never used, so spill it entirely to memory + if (C1XOptions.TraceLinearScanLevel >= 2) { + TTY.println(" spilling entire interval because split pos is at beginning of interval"); + TTY.println(" use positions: " + interval.usePosList().size()); + } + assert interval.firstUsage(RegisterPriority.ShouldHaveRegister) > currentPosition : "interval must not have use position before currentPosition"; + + allocator.assignSpillSlot(interval); + allocator.changeSpillState(interval, minSplitPos); + + // Also kick parent intervals out of register to memory when they have no use + // position. This avoids short interval in register surrounded by intervals in + // memory . avoid useless moves from memory to register and back + Interval parent = interval; + while (parent != null && parent.isSplitChild()) { + parent = parent.getSplitChildBeforeOpId(parent.from()); + + if (parent.location().isRegister()) { + if (parent.firstUsage(RegisterPriority.ShouldHaveRegister) == Integer.MAX_VALUE) { + // parent is never used, so kick it out of its assigned register + if (C1XOptions.TraceLinearScanLevel >= 4) { + TTY.println(" kicking out interval %d out of its register because it is never used", parent.operandNumber); + } + allocator.assignSpillSlot(parent); + } else { + // do not go further back because the register is actually used by the interval + parent = null; + } + } + } + + } else { + // search optimal split pos, split interval and spill only the right hand part + int optimalSplitPos = findOptimalSplitPos(interval, minSplitPos, maxSplitPos, false); + + assert minSplitPos <= optimalSplitPos && optimalSplitPos <= maxSplitPos : "out of range"; + assert optimalSplitPos < interval.to() : "cannot split at end of interval"; + assert optimalSplitPos >= interval.from() : "cannot split before start of interval"; + + if (!allocator.isBlockBegin(optimalSplitPos)) { + // move position before actual instruction (odd opId) + optimalSplitPos = (optimalSplitPos - 1) | 1; + } + + if (C1XOptions.TraceLinearScanLevel >= 4) { + TTY.println(" splitting at position %d", optimalSplitPos); + } + assert allocator.isBlockBegin(optimalSplitPos) || (optimalSplitPos % 2 == 1) : "split pos must be odd when not on block boundary"; + assert !allocator.isBlockBegin(optimalSplitPos) || (optimalSplitPos % 2 == 0) : "split pos must be even on block boundary"; + + Interval spilledPart = interval.split(optimalSplitPos, allocator); + allocator.assignSpillSlot(spilledPart); + allocator.changeSpillState(spilledPart, optimalSplitPos); + + if (!allocator.isBlockBegin(optimalSplitPos)) { + if (C1XOptions.TraceLinearScanLevel >= 4) { + TTY.println(" inserting move from interval %d to %d", interval.operandNumber, spilledPart.operandNumber); + } + insertMove(optimalSplitPos, interval, spilledPart); + } + + // the currentSplitChild is needed later when moves are inserted for reloading + assert spilledPart.currentSplitChild() == interval : "overwriting wrong currentSplitChild"; + spilledPart.makeCurrentSplitChild(); + + if (C1XOptions.TraceLinearScanLevel >= 2) { + TTY.println(" split interval in two parts"); + TTY.print(" "); + TTY.println(interval.logString(allocator)); + TTY.print(" "); + TTY.println(spilledPart.logString(allocator)); + } + } + } + + void splitStackInterval(Interval interval) { + int minSplitPos = currentPosition + 1; + int maxSplitPos = Math.min(interval.firstUsage(RegisterPriority.ShouldHaveRegister), interval.to()); + + splitBeforeUsage(interval, minSplitPos, maxSplitPos); + } + + void splitWhenPartialRegisterAvailable(Interval interval, int registerAvailableUntil) { + int minSplitPos = Math.max(interval.previousUsage(RegisterPriority.ShouldHaveRegister, registerAvailableUntil), interval.from() + 1); + splitBeforeUsage(interval, minSplitPos, registerAvailableUntil); + } + + void splitAndSpillInterval(Interval interval) { + assert interval.state == State.Active || interval.state == State.Inactive : "other states not allowed"; + + int currentPos = currentPosition; + if (interval.state == State.Inactive) { + // the interval is currently inactive, so no spill slot is needed for now. + // when the split part is activated, the interval has a new chance to get a register, + // so in the best case no stack slot is necessary + assert interval.hasHoleBetween(currentPos - 1, currentPos + 1) : "interval can not be inactive otherwise"; + splitBeforeUsage(interval, currentPos + 1, currentPos + 1); + + } else { + // search the position where the interval must have a register and split + // at the optimal position before. + // The new created part is added to the unhandled list and will get a register + // when it is activated + int minSplitPos = currentPos + 1; + int maxSplitPos = Math.min(interval.nextUsage(RegisterPriority.MustHaveRegister, minSplitPos), interval.to()); + + splitBeforeUsage(interval, minSplitPos, maxSplitPos); + + assert interval.nextUsage(RegisterPriority.MustHaveRegister, currentPos) == Integer.MAX_VALUE : "the remaining part is spilled to stack and therefore has no register"; + splitForSpilling(interval); + } + } + + boolean allocFreeRegister(Interval interval) { + if (C1XOptions.TraceLinearScanLevel >= 2) { + TTY.println("trying to find free register for " + interval.logString(allocator)); + } + + initUseLists(true); + freeExcludeActiveFixed(); + freeExcludeActiveAny(); + freeCollectInactiveFixed(interval); + freeCollectInactiveAny(interval); + // freeCollectUnhandled(fixedKind, cur); + assert unhandledLists.get(RegisterBinding.Fixed) == Interval.EndMarker : "must not have unhandled fixed intervals because all fixed intervals have a use at position 0"; + + // usePos contains the start of the next interval that has this register assigned + // (either as a fixed register or a normal allocated register in the past) + // only intervals overlapping with cur are processed, non-overlapping invervals can be ignored safely + if (C1XOptions.TraceLinearScanLevel >= 4) { + TTY.println(" state of registers:"); + for (CiRegister register : availableRegs) { + int i = register.number; + TTY.println(" reg %d: usePos: %d", register.number, usePos[i]); + } + } + + CiRegister hint = null; + Interval locationHint = interval.locationHint(true, allocator); + if (locationHint != null && locationHint.location() != null && locationHint.location().isRegister()) { + hint = locationHint.location().asRegister(); + if (C1XOptions.TraceLinearScanLevel >= 4) { + TTY.println(" hint register %d from interval %s", hint.number, locationHint.logString(allocator)); + } + } + assert interval.location() == null : "register already assigned to interval"; + + // the register must be free at least until this position + int regNeededUntil = interval.from() + 1; + int intervalTo = interval.to(); + + boolean needSplit = false; + int splitPos = -1; + + CiRegister reg = null; + CiRegister minFullReg = null; + CiRegister maxPartialReg = null; + + for (int i = 0; i < availableRegs.length; ++i) { + CiRegister availableReg = availableRegs[i]; + int number = availableReg.number; + if (usePos[number] >= intervalTo) { + // this register is free for the full interval + if (minFullReg == null || availableReg == hint || (usePos[number] < usePos[minFullReg.number] && minFullReg != hint)) { + minFullReg = availableReg; + } + } else if (usePos[number] > regNeededUntil) { + // this register is at least free until regNeededUntil + if (maxPartialReg == null || availableReg == hint || (usePos[number] > usePos[maxPartialReg.number] && maxPartialReg != hint)) { + maxPartialReg = availableReg; + } + } + } + + if (minFullReg != null) { + reg = minFullReg; + } else if (maxPartialReg != null) { + needSplit = true; + reg = maxPartialReg; + } else { + return false; + } + + splitPos = usePos[reg.number]; + interval.assignLocation(reg.asValue(interval.kind())); + if (C1XOptions.TraceLinearScanLevel >= 2) { + TTY.println("selected register %d", reg.number); + } + + assert splitPos > 0 : "invalid splitPos"; + if (needSplit) { + // register not available for full interval, so split it + splitWhenPartialRegisterAvailable(interval, splitPos); + } + + // only return true if interval is completely assigned + return true; + } + + CiRegister findLockedRegister(int regNeededUntil, int intervalTo, CiValue ignoreReg, boolean[] needSplit) { + int maxReg = -1; + CiRegister ignore = ignoreReg.isRegister() ? ignoreReg.asRegister() : null; + + for (CiRegister reg : availableRegs) { + int i = reg.number; + if (reg == ignore) { + // this register must be ignored + + } else if (usePos[i] > regNeededUntil) { + if (maxReg == -1 || (usePos[i] > usePos[maxReg])) { + maxReg = i; + } + } + } + + if (maxReg != -1) { + if (blockPos[maxReg] <= intervalTo) { + needSplit[0] = true; + } + return availableRegs[maxReg]; + } + + return null; + } + + void splitAndSpillIntersectingIntervals(CiRegister reg) { + assert reg != null : "no register assigned"; + + for (int i = 0; i < spillIntervals[reg.number].size(); i++) { + Interval interval = spillIntervals[reg.number].get(i); + removeFromList(interval); + splitAndSpillInterval(interval); + } + } + + // Split an Interval and spill it to memory so that cur can be placed in a register + void allocLockedRegister(Interval interval) { + if (C1XOptions.TraceLinearScanLevel >= 2) { + TTY.println("need to split and spill to get register for " + interval.logString(allocator)); + } + + // collect current usage of registers + initUseLists(false); + spillExcludeActiveFixed(); + // spillBlockUnhandledFixed(cur); + assert unhandledLists.get(RegisterBinding.Fixed) == Interval.EndMarker : "must not have unhandled fixed intervals because all fixed intervals have a use at position 0"; + spillBlockInactiveFixed(interval); + spillCollectActiveAny(); + spillCollectInactiveAny(interval); + + if (C1XOptions.TraceLinearScanLevel >= 4) { + TTY.println(" state of registers:"); + for (CiRegister reg : availableRegs) { + int i = reg.number; + TTY.print(" reg %d: usePos: %d, blockPos: %d, intervals: ", i, usePos[i], blockPos[i]); + for (int j = 0; j < spillIntervals[i].size(); j++) { + TTY.print("%d ", spillIntervals[i].get(j).operandNumber); + } + TTY.println(); + } + } + + // the register must be free at least until this position + int firstUsage = interval.firstUsage(RegisterPriority.MustHaveRegister); + int regNeededUntil = Math.min(firstUsage, interval.from() + 1); + int intervalTo = interval.to(); + assert regNeededUntil > 0 && regNeededUntil < Integer.MAX_VALUE : "interval has no use"; + + CiRegister reg = null; + CiRegister ignore = interval.location() != null && interval.location().isRegister() ? interval.location().asRegister() : null; + for (CiRegister availableReg : availableRegs) { + int number = availableReg.number; + if (availableReg == ignore) { + // this register must be ignored + } else if (usePos[number] > regNeededUntil) { + if (reg == null || (usePos[number] > usePos[reg.number])) { + reg = availableReg; + } + } + } + + if (reg == null || usePos[reg.number] <= firstUsage) { + // the first use of cur is later than the spilling position -> spill cur + if (C1XOptions.TraceLinearScanLevel >= 4) { + TTY.println("able to spill current interval. firstUsage(register): %d, usePos: %d", firstUsage, reg == null ? 0 : usePos[reg.number]); + } + + if (firstUsage <= interval.from() + 1) { + assert false : "cannot spill interval that is used in first instruction (possible reason: no register found) firstUsage=" + firstUsage + ", interval.from()=" + interval.from(); + // assign a reasonable register and do a bailout in product mode to avoid errors + allocator.assignSpillSlot(interval); + throw new CiBailout("LinearScan: no register found"); + } + + splitAndSpillInterval(interval); + return; + } + + boolean needSplit = blockPos[reg.number] <= intervalTo; + + int splitPos = blockPos[reg.number]; + + if (C1XOptions.TraceLinearScanLevel >= 4) { + TTY.println("decided to use register %d", reg.number); + } + assert splitPos > 0 : "invalid splitPos"; + assert needSplit || splitPos > interval.from() : "splitting interval at from"; + + interval.assignLocation(reg.asValue(interval.kind())); + if (needSplit) { + // register not available for full interval : so split it + splitWhenPartialRegisterAvailable(interval, splitPos); + } + + // perform splitting and spilling for all affected intervals + splitAndSpillIntersectingIntervals(reg); + } + + boolean noAllocationPossible(Interval interval) { + + if (compilation.target.arch.isX86()) { + // fast calculation of intervals that can never get a register because the + // the next instruction is a call that blocks all registers + // Note: this does not work if callee-saved registers are available (e.g. on Sparc) + + // check if this interval is the result of a split operation + // (an interval got a register until this position) + int pos = interval.from(); + if (isOdd(pos)) { + // the current instruction is a call that blocks all registers + if (pos < allocator.maxOpId() && allocator.hasCall(pos + 1) && interval.to() > pos + 1) { + if (C1XOptions.TraceLinearScanLevel >= 4) { + TTY.println(" free register cannot be available because all registers blocked by following call"); + } + + // safety check that there is really no register available + assert !allocFreeRegister(interval) : "found a register for this interval"; + return true; + } + + } + } + return false; + } + + void initVarsForAlloc(Interval interval) { + EnumMap categorizedRegs = allocator.compilation.registerConfig.getCategorizedAllocatableRegisters(); + if (allocator.operands.mustBeByteRegister(interval.operand)) { + assert interval.kind() != CiKind.Float && interval.kind() != CiKind.Double : "cpu regs only"; + availableRegs = categorizedRegs.get(RegisterFlag.Byte); + } else if (interval.kind() == CiKind.Float || interval.kind() == CiKind.Double) { + availableRegs = categorizedRegs.get(RegisterFlag.FPU); + } else { + availableRegs = categorizedRegs.get(RegisterFlag.CPU); + } + } + + boolean isMove(LIRInstruction op, Interval from, Interval to) { + if (op.code != LIROpcode.Move) { + return false; + } + assert op instanceof LIROp1 : "move must be LIROp1"; + + CiValue input = ((LIROp1) op).operand(); + CiValue result = ((LIROp1) op).result(); + return input.isVariable() && result.isVariable() && input == from.operand && result == to.operand; + } + + // optimization (especially for phi functions of nested loops): + // assign same spill slot to non-intersecting intervals + void combineSpilledIntervals(Interval interval) { + if (interval.isSplitChild()) { + // optimization is only suitable for split parents + return; + } + + Interval registerHint = interval.locationHint(false, allocator); + if (registerHint == null) { + // cur is not the target of a move : otherwise registerHint would be set + return; + } + assert registerHint.isSplitParent() : "register hint must be split parent"; + + if (interval.spillState() != SpillState.NoOptimization || registerHint.spillState() != SpillState.NoOptimization) { + // combining the stack slots for intervals where spill move optimization is applied + // is not benefitial and would cause problems + return; + } + + int beginPos = interval.from(); + int endPos = interval.to(); + if (endPos > allocator.maxOpId() || isOdd(beginPos) || isOdd(endPos)) { + // safety check that lirOpWithId is allowed + return; + } + + if (!isMove(allocator.instructionForId(beginPos), registerHint, interval) || !isMove(allocator.instructionForId(endPos), interval, registerHint)) { + // cur and registerHint are not connected with two moves + return; + } + + Interval beginHint = registerHint.getSplitChildAtOpId(beginPos, LIRInstruction.OperandMode.Input, allocator); + Interval endHint = registerHint.getSplitChildAtOpId(endPos, LIRInstruction.OperandMode.Output, allocator); + if (beginHint == endHint || beginHint.to() != beginPos || endHint.from() != endPos) { + // registerHint must be split : otherwise the re-writing of use positions does not work + return; + } + + assert beginHint.location() != null : "must have register assigned"; + assert endHint.location() == null : "must not have register assigned"; + assert interval.firstUsage(RegisterPriority.MustHaveRegister) == beginPos : "must have use position at begin of interval because of move"; + assert endHint.firstUsage(RegisterPriority.MustHaveRegister) == endPos : "must have use position at begin of interval because of move"; + + if (beginHint.location().isRegister()) { + // registerHint is not spilled at beginPos : so it would not be benefitial to immediately spill cur + return; + } + assert registerHint.spillSlot() != null : "must be set when part of interval was spilled"; + + // modify intervals such that cur gets the same stack slot as registerHint + // delete use positions to prevent the intervals to get a register at beginning + interval.setSpillSlot(registerHint.spillSlot()); + interval.removeFirstUsePos(); + endHint.removeFirstUsePos(); + } + + // allocate a physical register or memory location to an interval + @Override + boolean activateCurrent() { + Interval interval = current; + boolean result = true; + + if (C1XOptions.TraceLinearScanLevel >= 2) { + TTY.println("+++++ activating interval " + interval.logString(allocator)); + } + + if (C1XOptions.TraceLinearScanLevel >= 4) { + TTY.println(" splitParent: %s, insertMoveWhenActivated: %b", interval.splitParent().operandNumber, interval.insertMoveWhenActivated()); + } + + final CiValue operand = interval.operand; + if (interval.location() != null && interval.location().isStackSlot()) { + // activating an interval that has a stack slot assigned . split it at first use position + // used for method parameters + if (C1XOptions.TraceLinearScanLevel >= 4) { + TTY.println(" interval has spill slot assigned (method parameter) . split it before first use"); + } + splitStackInterval(interval); + result = false; + + } else { + if (operand.isVariable() && allocator.operands.mustStartInMemory((CiVariable) operand)) { + assert interval.location() == null : "register already assigned"; + allocator.assignSpillSlot(interval); + + if (!allocator.operands.mustStayInMemory((CiVariable) operand)) { + // activating an interval that must start in a stack slot but may get a register later + // used for lirRoundfp: rounding is done by store to stack and reload later + if (C1XOptions.TraceLinearScanLevel >= 4) { + TTY.println(" interval must start in stack slot . split it before first use"); + } + splitStackInterval(interval); + } + + result = false; + } else if (interval.location() == null) { + // interval has not assigned register . normal allocation + // (this is the normal case for most intervals) + if (C1XOptions.TraceLinearScanLevel >= 4) { + TTY.println(" normal allocation of register"); + } + + // assign same spill slot to non-intersecting intervals + combineSpilledIntervals(interval); + + initVarsForAlloc(interval); + if (noAllocationPossible(interval) || !allocFreeRegister(interval)) { + // no empty register available. + // split and spill another interval so that this interval gets a register + allocLockedRegister(interval); + } + + // spilled intervals need not be move to active-list + if (!interval.location().isRegister()) { + result = false; + } + } + } + + // load spilled values that become active from stack slot to register + if (interval.insertMoveWhenActivated()) { + assert interval.isSplitChild(); + assert interval.currentSplitChild() != null; + assert interval.currentSplitChild().operand != operand : "cannot insert move between same interval"; + if (C1XOptions.TraceLinearScanLevel >= 4) { + TTY.println("Inserting move from interval %d to %d because insertMoveWhenActivated is set", interval.currentSplitChild().operandNumber, interval.operandNumber); + } + + insertMove(interval.from(), interval.currentSplitChild(), interval); + } + interval.makeCurrentSplitChild(); + + return result; // true = interval is moved to active list + } + + public void finishAllocation() { + // must be called when all intervals are allocated + moveResolver.resolveAndAppendMoves(); + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/MoveResolver.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/MoveResolver.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,367 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.alloc; + +import java.util.*; + +import com.oracle.max.graal.compiler.*; +import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.compiler.lir.*; +import com.oracle.max.graal.compiler.util.*; +import com.sun.cri.ci.*; + +/** + * + * @author Thomas Wuerthinger + */ +final class MoveResolver { + + private final LinearScan allocator; + + private LIRList insertList; + private int insertIdx; + private LIRInsertionBuffer insertionBuffer; // buffer where moves are inserted + + private final List mappingFrom; + private final List mappingFromOpr; + private final List mappingTo; + private boolean multipleReadsAllowed; + private final int[] registerBlocked; + + private int registerBlocked(int reg) { + return registerBlocked[reg]; + } + + private void setRegisterBlocked(int reg, int direction) { + assert direction == 1 || direction == -1 : "out of bounds"; + registerBlocked[reg] += direction; + } + + void setMultipleReadsAllowed() { + multipleReadsAllowed = true; + } + + boolean hasMappings() { + return mappingFrom.size() > 0; + } + + MoveResolver(LinearScan allocator) { + + this.allocator = allocator; + this.multipleReadsAllowed = false; + this.mappingFrom = new ArrayList(8); + this.mappingFromOpr = new ArrayList(8); + this.mappingTo = new ArrayList(8); + this.insertIdx = -1; + this.insertionBuffer = new LIRInsertionBuffer(); + this.registerBlocked = new int[allocator.registers.length]; + assert checkEmpty(); + } + + boolean checkEmpty() { + assert mappingFrom.size() == 0 && mappingFromOpr.size() == 0 && mappingTo.size() == 0 : "list must be empty before and after processing"; + for (int i = 0; i < allocator.registers.length; i++) { + assert registerBlocked(i) == 0 : "register map must be empty before and after processing"; + } + assert !multipleReadsAllowed : "must have default value"; + return true; + } + + private boolean verifyBeforeResolve() { + assert mappingFrom.size() == mappingFromOpr.size() : "length must be equal"; + assert mappingFrom.size() == mappingTo.size() : "length must be equal"; + assert insertList != null && insertIdx != -1 : "insert position not set"; + + int i; + int j; + if (!multipleReadsAllowed) { + for (i = 0; i < mappingFrom.size(); i++) { + for (j = i + 1; j < mappingFrom.size(); j++) { + assert mappingFrom.get(i) == null || mappingFrom.get(i) != mappingFrom.get(j) : "cannot read from same interval twice"; + } + } + } + + for (i = 0; i < mappingTo.size(); i++) { + for (j = i + 1; j < mappingTo.size(); j++) { + assert mappingTo.get(i) != mappingTo.get(j) : "cannot write to same interval twice"; + } + } + + HashSet usedRegs = new HashSet(); + if (!multipleReadsAllowed) { + for (i = 0; i < mappingFrom.size(); i++) { + Interval interval = mappingFrom.get(i); + if (interval != null) { + boolean unique = usedRegs.add(interval.location()); + assert unique : "cannot read from same register twice"; + } + } + } + + usedRegs.clear(); + for (i = 0; i < mappingTo.size(); i++) { + Interval interval = mappingTo.get(i); + boolean unique = usedRegs.add(interval.location()); + assert unique : "cannot write to same register twice"; + } + + usedRegs.clear(); + for (i = 0; i < mappingFrom.size(); i++) { + Interval interval = mappingFrom.get(i); + if (interval != null && !interval.location().isRegister()) { + usedRegs.add(interval.location()); + } + } + for (i = 0; i < mappingTo.size(); i++) { + Interval interval = mappingTo.get(i); + assert !usedRegs.contains(interval.location()) || interval.location() == mappingFrom.get(i).location() : "stack slots used in mappingFrom must be disjoint to mappingTo"; + } + + return true; + } + + // mark assignedReg and assignedRegHi of the interval as blocked + private void blockRegisters(Interval interval) { + CiValue location = interval.location(); + if (location.isRegister()) { + int reg = location.asRegister().number; + assert multipleReadsAllowed || registerBlocked(reg) == 0 : "register already marked as used"; + setRegisterBlocked(reg, 1); + } + } + + // mark assignedReg and assignedRegHi of the interval as unblocked + private void unblockRegisters(Interval interval) { + CiValue location = interval.location(); + if (location.isRegister()) { + int reg = location.asRegister().number; + assert registerBlocked(reg) > 0 : "register already marked as unused"; + setRegisterBlocked(reg, -1); + } + } + + /** + * Checks if the {@linkplain Interval#location() location} of {@code to} is not blocked + * or is only blocked by {@code from}. + */ + private boolean safeToProcessMove(Interval from, Interval to) { + CiValue fromReg = from != null ? from.location() : null; + + CiValue reg = to.location(); + if (reg.isRegister()) { + if (registerBlocked(reg.asRegister().number) > 1 || (registerBlocked(reg.asRegister().number) == 1 && reg != fromReg)) { + return false; + } + } + + return true; + } + + private void createInsertionBuffer(LIRList list) { + assert !insertionBuffer.initialized() : "overwriting existing buffer"; + insertionBuffer.init(list); + } + + private void appendInsertionBuffer() { + if (insertionBuffer.initialized()) { + insertionBuffer.lirList().append(insertionBuffer); + } + assert !insertionBuffer.initialized() : "must be uninitialized now"; + + insertList = null; + insertIdx = -1; + } + + private void insertMove(Interval fromInterval, Interval toInterval) { + assert fromInterval.operand != toInterval.operand : "from and to interval equal: " + fromInterval; + assert Util.archKindsEqual(fromInterval.kind(), toInterval.kind()) : "move between different types"; + assert insertList != null && insertIdx != -1 : "must setup insert position first"; + assert insertionBuffer.lirList() == insertList : "wrong insertion buffer"; + + CiValue fromOpr = fromInterval.operand; + CiValue toOpr = toInterval.operand; + + insertionBuffer.move(insertIdx, fromOpr, toOpr, null); + + if (C1XOptions.TraceLinearScanLevel >= 4) { + TTY.println("MoveResolver: inserted move from %d (%s) to %d (%s)", fromInterval.operandNumber, fromInterval.location(), toInterval.operandNumber, toInterval.location()); + } + } + + private void insertMove(CiValue fromOpr, Interval toInterval) { + assert Util.archKindsEqual(fromOpr.kind, toInterval.kind()) : "move between different types"; + assert insertList != null && insertIdx != -1 : "must setup insert position first"; + assert insertionBuffer.lirList() == insertList : "wrong insertion buffer"; + + CiValue toOpr = toInterval.operand; + insertionBuffer.move(insertIdx, fromOpr, toOpr, null); + + if (C1XOptions.TraceLinearScanLevel >= 4) { + TTY.print("MoveResolver: inserted move from constant %s to %d (%s)", fromOpr, toInterval.operandNumber, toInterval.location()); + } + } + + private void resolveMappings() { + //if (C1XOptions.TraceLinearScanLevel >= 4) TTY.println("MoveResolver: resolving mappings for Block B%d, index %d", insertList.block() != null ? insertList.block().blockID : -1, insertIdx); + assert verifyBeforeResolve(); + + // Block all registers that are used as input operands of a move. + // When a register is blocked, no move to this register is emitted. + // This is necessary for detecting cycles in moves. + int i; + for (i = mappingFrom.size() - 1; i >= 0; i--) { + Interval fromInterval = mappingFrom.get(i); + if (fromInterval != null) { + blockRegisters(fromInterval); + } + } + + int spillCandidate = -1; + while (mappingFrom.size() > 0) { + boolean processedInterval = false; + + for (i = mappingFrom.size() - 1; i >= 0; i--) { + Interval fromInterval = mappingFrom.get(i); + Interval toInterval = mappingTo.get(i); + + if (safeToProcessMove(fromInterval, toInterval)) { + // this interval can be processed because target is free + if (fromInterval != null) { + insertMove(fromInterval, toInterval); + unblockRegisters(fromInterval); + } else { + insertMove(mappingFromOpr.get(i), toInterval); + } + mappingFrom.remove(i); + mappingFromOpr.remove(i); + mappingTo.remove(i); + + processedInterval = true; + } else if (fromInterval != null && fromInterval.location().isRegister()) { + // this interval cannot be processed now because target is not free + // it starts in a register, so it is a possible candidate for spilling + spillCandidate = i; + } + } + + if (!processedInterval) { + // no move could be processed because there is a cycle in the move list + // (e.g. r1 . r2, r2 . r1), so one interval must be spilled to memory + assert spillCandidate != -1 : "no interval in register for spilling found"; + + // create a new spill interval and assign a stack slot to it + Interval fromInterval = mappingFrom.get(spillCandidate); + Interval spillInterval = allocator.createDerivedInterval(fromInterval); + spillInterval.setKind(fromInterval.kind()); + + // add a dummy range because real position is difficult to calculate + // Note: this range is a special case when the integrity of the allocation is checked + spillInterval.addRange(1, 2); + + // do not allocate a new spill slot for temporary interval, but + // use spill slot assigned to fromInterval. Otherwise moves from + // one stack slot to another can happen (not allowed by LIRAssembler + CiStackSlot spillSlot = fromInterval.spillSlot(); + if (spillSlot == null) { + spillSlot = allocator.allocateSpillSlot(spillInterval.kind()); + fromInterval.setSpillSlot(spillSlot); + } + spillInterval.assignLocation(spillSlot); + + if (C1XOptions.TraceLinearScanLevel >= 4) { + TTY.println("created new Interval %s for spilling", spillInterval.operand); + } + + // insert a move from register to stack and update the mapping + insertMove(fromInterval, spillInterval); + mappingFrom.set(spillCandidate, spillInterval); + unblockRegisters(fromInterval); + } + } + + // reset to default value + multipleReadsAllowed = false; + + // check that all intervals have been processed + assert checkEmpty(); + } + + void setInsertPosition(LIRList insertList, int insertIdx) { + //if (C1XOptions.TraceLinearScanLevel >= 4) TTY.println("MoveResolver: setting insert position to Block B%d, index %d", insertList.block() != null ? insertList.block().blockID : -1, insertIdx); + assert this.insertList == null && this.insertIdx == -1 : "use moveInsertPosition instead of setInsertPosition when data already set"; + + createInsertionBuffer(insertList); + this.insertList = insertList; + this.insertIdx = insertIdx; + } + + void moveInsertPosition(LIRList insertList, int insertIdx) { + //if (C1XOptions.TraceLinearScanLevel >= 4) TTY.println("MoveResolver: moving insert position to Block B%d, index %d", (insertList != null && insertList.block() != null) ? insertList.block().blockID : -1, insertIdx); + + if (this.insertList != null && (this.insertList != insertList || this.insertIdx != insertIdx)) { + // insert position changed . resolve current mappings + resolveMappings(); + } + + if (this.insertList != insertList) { + // block changed . append insertionBuffer because it is + // bound to a specific block and create a new insertionBuffer + appendInsertionBuffer(); + createInsertionBuffer(insertList); + } + + this.insertList = insertList; + this.insertIdx = insertIdx; + } + + void addMapping(Interval fromInterval, Interval toInterval) { + if (C1XOptions.TraceLinearScanLevel >= 4) { + TTY.println("MoveResolver: adding mapping from interval %d (%s) to interval %d (%s)", fromInterval.operandNumber, fromInterval.location(), toInterval.operandNumber, toInterval.location()); + } + + assert fromInterval.operand != toInterval.operand : "from and to interval equal: " + fromInterval; + assert Util.archKindsEqual(fromInterval.kind(), toInterval.kind()); + mappingFrom.add(fromInterval); + mappingFromOpr.add(CiValue.IllegalValue); + mappingTo.add(toInterval); + } + + void addMapping(CiValue fromOpr, Interval toInterval) { + if (C1XOptions.TraceLinearScanLevel >= 4) { + TTY.println("MoveResolver: adding mapping from %s to %d (%s)", fromOpr, toInterval.operandNumber, toInterval.location()); + } + assert fromOpr.isConstant() : "only for constants"; + + mappingFrom.add(null); + mappingFromOpr.add(fromOpr); + mappingTo.add(toInterval); + } + + void resolveAndAppendMoves() { + if (hasMappings()) { + resolveMappings(); + } + appendInsertionBuffer(); + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/OperandPool.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/OperandPool.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,268 @@ +/* + * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.alloc; + +import java.util.*; + +import com.oracle.max.graal.compiler.*; +import com.oracle.max.graal.compiler.ir.*; +import com.sun.cri.ci.*; + +/** + * An ordered, 0-based indexable pool of instruction operands for a method being compiled. + * The physical {@linkplain CiRegister registers} of the platform occupy the front of the + * pool (starting at index 0) followed by {@linkplain CiVariable variable} operands. + * The index of an operand in the pool is its {@linkplain #operandNumber(CiValue) operand number}. + * + * In the original HotSpot C1 source code, this pool corresponds to the + * "flat register file" mentioned in c1_LinearScan.cpp. + * + * @author Doug Simon + */ +public final class OperandPool { + + public static final int INITIAL_VARIABLE_CAPACITY = 20; + + /** + * The physical registers occupying the head of the operand pool. This is the complete + * {@linkplain CiArchitecture#registers register set} of the target architecture, not + * just the allocatable registers. + */ + private final CiRegister[] registers; + + /** + * The variable operands allocated from this pool. The {@linkplain #operandNumber(CiValue) number} + * of the first variable operand in this pool is one greater than the number of the last + * register operand in the pool. + */ + private final ArrayList variables; + + /** + * Map from a {@linkplain CiVariable#index variable index} to the instruction whose result is stored in the denoted variable. + * This map is only populated and used if {@link C1XOptions#DetailedAsserts} is {@code true}. + */ + private final ArrayList variableDefs; + + /** + * The {@linkplain #operandNumber(CiValue) number} of the first variable operand + * {@linkplain #newVariable(CiKind) allocated} from this pool. + */ + private final int firstVariableNumber; + + /** + * Records which variable operands have the {@link VariableFlag#MustBeByteRegister} flag set. + */ + private CiBitMap mustBeByteRegister; + + /** + * Records which variable operands have the {@link VariableFlag#MustStartInMemory} flag set. + */ + private CiBitMap mustStartInMemory; + + /** + * Records which variable operands have the {@link VariableFlag#MustStayInMemory} flag set. + */ + private CiBitMap mustStayInMemory; + + /** + * Flags that can be set for {@linkplain CiValue#isVariable() variable} operands. + */ + public enum VariableFlag { + /** + * Denotes a variable that needs to be assigned a memory location + * at the beginning, but may then be loaded in a register. + */ + MustStartInMemory, + + /** + * Denotes a variable that needs to be assigned a memory location + * at the beginning and never subsequently loaded in a register. + */ + MustStayInMemory, + + /** + * Denotes a variable that must be assigned to a byte-sized register. + */ + MustBeByteRegister; + + public static final VariableFlag[] VALUES = values(); + } + + private static CiBitMap set(CiBitMap map, CiVariable variable) { + if (map == null) { + int length = CiBitMap.roundUpLength(variable.index + 1); + map = new CiBitMap(length); + } else if (map.size() <= variable.index) { + int length = CiBitMap.roundUpLength(variable.index + 1); + map.grow(length); + } + map.set(variable.index); + return map; + } + + private static boolean get(CiBitMap map, CiVariable variable) { + if (map == null || map.size() <= variable.index) { + return false; + } + return map.get(variable.index); + } + + /** + * Creates a new operand pool. + * + * @param target description of the target architecture for a compilation + */ + public OperandPool(CiTarget target) { + CiRegister[] registers = target.arch.registers; + this.firstVariableNumber = registers.length; + this.registers = registers; + variables = new ArrayList(INITIAL_VARIABLE_CAPACITY); + variableDefs = C1XOptions.DetailedAsserts ? new ArrayList(INITIAL_VARIABLE_CAPACITY) : null; + } + + /** + * Creates a new {@linkplain CiVariable variable} operand. + * + * @param kind the kind of the variable + * @return a new variable + */ + public CiVariable newVariable(CiKind kind) { + return newVariable(kind, kind == CiKind.Boolean || kind == CiKind.Byte ? VariableFlag.MustBeByteRegister : null); + } + + /** + * Creates a new {@linkplain CiVariable variable} operand. + * + * @param kind the kind of the variable + * @param flag a flag that is set for the new variable operand (ignored if {@code null}) + * @return a new variable operand + */ + public CiVariable newVariable(CiKind kind, VariableFlag flag) { + assert kind != CiKind.Void; + int varIndex = variables.size(); + CiVariable var = CiVariable.get(kind, varIndex); + if (flag == VariableFlag.MustBeByteRegister) { + mustBeByteRegister = set(mustBeByteRegister, var); + } else if (flag == VariableFlag.MustStartInMemory) { + mustStartInMemory = set(mustStartInMemory, var); + } else if (flag == VariableFlag.MustStayInMemory) { + mustStayInMemory = set(mustStayInMemory, var); + } else { + assert flag == null; + } + variables.add(var); + return var; + } + + /** + * Gets the unique number for an operand contained in this pool. + * + * + * @param operand an operand + * @return the unique number for {@code operand} in the range {@code [0 .. size())} + */ + public int operandNumber(CiValue operand) { + if (operand.isRegister()) { + int number = operand.asRegister().number; + assert number < firstVariableNumber; + return number; + } + assert operand.isVariable(); + return firstVariableNumber + ((CiVariable) operand).index; + } + + /** + * Gets the operand in this pool denoted by a given operand number. + * + * @param operandNumber a value that must be in the range {@code [0 .. size())} + * @return the operand in this pool denoted by {@code operandNumber} + */ + public CiValue operandFor(int operandNumber) { + if (operandNumber < firstVariableNumber) { + assert operandNumber >= 0; + return registers[operandNumber].asValue(); + } + int index = operandNumber - firstVariableNumber; + CiVariable variable = variables.get(index); + assert variable.index == index; + return variable; + } + + /** + * Records that the result of {@code instruction} is stored in {@code result}. + * + * @param result the variable storing the result of {@code instruction} + * @param instruction an instruction that produces a result (i.e. pushes a value to the stack) + */ + public void recordResult(CiVariable result, Value instruction) { + while (variableDefs.size() <= result.index) { + variableDefs.add(null); + } + variableDefs.set(result.index, instruction); + } + + /** + * Gets the instruction whose result is recorded in a given variable. + * + * @param result the variable storing the result of an instruction + * @return the instruction that stores its result in {@code result} + */ + public Value instructionForResult(CiVariable result) { + if (variableDefs.size() > result.index) { + return variableDefs.get(result.index); + } + return null; + } + + public boolean mustStartInMemory(CiVariable operand) { + return get(mustStartInMemory, operand) || get(mustStayInMemory, operand); + } + + public boolean mustStayInMemory(CiVariable operand) { + return get(mustStayInMemory, operand); + } + + public boolean mustBeByteRegister(CiValue operand) { + return get(mustBeByteRegister, (CiVariable) operand); + } + + public void setMustBeByteRegister(CiVariable operand) { + mustBeByteRegister = set(mustBeByteRegister, operand); + } + + /** + * Gets the number of operands in this pool. This value will increase by 1 for + * each new variable operand {@linkplain #newVariable(CiKind) allocated} from this pool. + */ + public int size() { + return firstVariableNumber + variables.size(); + } + + /** + * Gets the highest operand number for a register operand in this pool. This value will + * never change for the lifetime of this pool. + */ + public int maxRegisterNumber() { + return firstVariableNumber - 1; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/Range.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/Range.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.alloc; + + +/** + * Represents a range of integers from a start (inclusive) to an end (exclusive. + * + * @author Thomas Wuerthinger + */ +public final class Range { + + public static final Range EndMarker = new Range(Integer.MAX_VALUE, Integer.MAX_VALUE, null); + + /** + * The start of the range, inclusive. + */ + public int from; + + /** + * The end of the range, exclusive. + */ + public int to; + + /** + * A link to allow the range to be put into a singly linked list. + */ + public Range next; + + boolean intersects(Range r) { + return intersectsAt(r) != -1; + } + + + /** + * Creates a new range. + * + * @param from the start of the range, inclusive + * @param to the end of the range, exclusive + * @param next link to the next range in a linked list + */ + Range(int from, int to, Range next) { + this.from = from; + this.to = to; + this.next = next; + } + + int intersectsAt(Range r2) { + Range r1 = this; + + assert r2 != null : "null ranges not allowed"; + assert r1 != EndMarker && r2 != EndMarker : "empty ranges not allowed"; + + do { + if (r1.from < r2.from) { + if (r1.to <= r2.from) { + r1 = r1.next; + if (r1 == EndMarker) { + return -1; + } + } else { + return r2.from; + } + } else { + if (r2.from < r1.from) { + if (r2.to <= r1.from) { + r2 = r2.next; + if (r2 == EndMarker) { + return -1; + } + } else { + return r1.from; + } + } else { // r1.from() == r2.from() + if (r1.from == r1.to) { + r1 = r1.next; + if (r1 == EndMarker) { + return -1; + } + } else { + if (r2.from == r2.to) { + r2 = r2.next; + if (r2 == EndMarker) { + return -1; + } + } else { + return r1.from; + } + } + } + } + } while (true); + } + + @Override + public String toString() { + return "[" + from + ", " + to + "]"; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/RegisterVerifier.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/RegisterVerifier.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,277 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.alloc; + +import java.util.*; + +import com.oracle.max.graal.compiler.*; +import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.compiler.lir.*; +import com.oracle.max.graal.compiler.util.*; +import com.sun.cri.ci.*; + +/** + * + * @author Thomas Wuerthinger + */ +final class RegisterVerifier { + + LinearScan allocator; + List workList; // all blocks that must be processed + ArrayMap savedStates; // saved information of previous check + + // simplified access to methods of LinearScan + C1XCompilation compilation() { + return allocator.compilation; + } + + Interval intervalAt(CiValue operand) { + return allocator.intervalFor(operand); + } + + // currently, only registers are processed + int stateSize() { + return allocator.operands.maxRegisterNumber() + 1; + } + + // accessors + Interval[] stateForBlock(LIRBlock block) { + return savedStates.get(block.blockID()); + } + + void setStateForBlock(LIRBlock block, Interval[] savedState) { + savedStates.put(block.blockID(), savedState); + } + + void addToWorkList(LIRBlock block) { + if (!workList.contains(block)) { + workList.add(block); + } + } + + RegisterVerifier(LinearScan allocator) { + this.allocator = allocator; + workList = new ArrayList(16); + this.savedStates = new ArrayMap(); + + } + + void verify(LIRBlock start) { + // setup input registers (method arguments) for first block + Interval[] inputState = new Interval[stateSize()]; + CiCallingConvention args = compilation().frameMap().incomingArguments(); + for (int n = 0; n < args.locations.length; n++) { + CiValue operand = args.locations[n]; + if (operand.isRegister()) { + CiValue reg = operand; + Interval interval = intervalAt(reg); + inputState[reg.asRegister().number] = interval; + } + } + + setStateForBlock(start, inputState); + addToWorkList(start); + + // main loop for verification + do { + LIRBlock block = workList.get(0); + workList.remove(0); + + processBlock(block); + } while (!workList.isEmpty()); + } + + private void processBlock(LIRBlock block) { + if (C1XOptions.TraceLinearScanLevel >= 2) { + TTY.println(); + TTY.println("processBlock B%d", block.blockID()); + } + + // must copy state because it is modified + Interval[] inputState = copy(stateForBlock(block)); + + if (C1XOptions.TraceLinearScanLevel >= 4) { + TTY.println("Input-State of intervals:"); + TTY.print(" "); + for (int i = 0; i < stateSize(); i++) { + if (inputState[i] != null) { + TTY.print(" %4d", inputState[i].operandNumber); + } else { + TTY.print(" __"); + } + } + TTY.println(); + TTY.println(); + } + + // process all operations of the block + processOperations(block.lir(), inputState); + + // iterate all successors + for (LIRBlock succ : block.blockSuccessors()) { + processSuccessor(succ, inputState); + } + } + + private void processSuccessor(LIRBlock block, Interval[] inputState) { + Interval[] savedState = stateForBlock(block); + + if (savedState != null) { + // this block was already processed before. + // check if new inputState is consistent with savedState + + boolean savedStateCorrect = true; + for (int i = 0; i < stateSize(); i++) { + if (inputState[i] != savedState[i]) { + // current inputState and previous savedState assume a different + // interval in this register . assume that this register is invalid + if (savedState[i] != null) { + // invalidate old calculation only if it assumed that + // register was valid. when the register was already invalid, + // then the old calculation was correct. + savedStateCorrect = false; + savedState[i] = null; + + if (C1XOptions.TraceLinearScanLevel >= 4) { + TTY.println("processSuccessor B%d: invalidating slot %d", block.blockID(), i); + } + } + } + } + + if (savedStateCorrect) { + // already processed block with correct inputState + if (C1XOptions.TraceLinearScanLevel >= 2) { + TTY.println("processSuccessor B%d: previous visit already correct", block.blockID()); + } + } else { + // must re-visit this block + if (C1XOptions.TraceLinearScanLevel >= 2) { + TTY.println("processSuccessor B%d: must re-visit because input state changed", block.blockID()); + } + addToWorkList(block); + } + + } else { + // block was not processed before, so set initial inputState + if (C1XOptions.TraceLinearScanLevel >= 2) { + TTY.println("processSuccessor B%d: initial visit", block.blockID()); + } + + setStateForBlock(block, copy(inputState)); + addToWorkList(block); + } + } + + Interval[] copy(Interval[] inputState) { + return inputState.clone(); + } + + void statePut(Interval[] inputState, CiValue location, Interval interval) { + if (location != null && location.isRegister()) { + CiRegister reg = location.asRegister(); + int regNum = reg.number; + if (interval != null) { + if (C1XOptions.TraceLinearScanLevel >= 4) { + TTY.println(" %s = %s", reg, interval.operand); + } + } else if (inputState[regNum] != null) { + if (C1XOptions.TraceLinearScanLevel >= 4) { + TTY.println(" %s = null", reg); + } + } + + inputState[regNum] = interval; + } + } + + boolean checkState(Interval[] inputState, CiValue reg, Interval interval) { + if (reg != null && reg.isRegister()) { + if (inputState[reg.asRegister().number] != interval) { + throw new CiBailout("!! Error in register allocation: register " + reg + " does not contain interval " + interval.operand + " but interval " + inputState[reg.asRegister().number]); + } + } + return true; + } + + void processOperations(LIRList ops, Interval[] inputState) { + // visit all instructions of the block + for (int i = 0; i < ops.length(); i++) { + LIRInstruction op = ops.at(i); + + if (C1XOptions.TraceLinearScanLevel >= 4) { + TTY.println(op.toStringWithIdPrefix()); + } + + // check if input operands are correct + int n = op.operandCount(LIRInstruction.OperandMode.Input); + for (int j = 0; j < n; j++) { + CiValue operand = op.operandAt(LIRInstruction.OperandMode.Input, j); + if (allocator.isProcessed(operand)) { + Interval interval = intervalAt(operand); + if (op.id != -1) { + interval = interval.getSplitChildAtOpId(op.id, LIRInstruction.OperandMode.Input, allocator); + } + + assert checkState(inputState, interval.location(), interval.splitParent()); + } + } + + // invalidate all caller save registers at calls + if (op.hasCall) { + for (CiRegister r : allocator.compilation.registerConfig.getCallerSaveRegisters()) { + statePut(inputState, r.asValue(), null); + } + } + + // set temp operands (some operations use temp operands also as output operands, so can't set them null) + n = op.operandCount(LIRInstruction.OperandMode.Temp); + for (int j = 0; j < n; j++) { + CiValue operand = op.operandAt(LIRInstruction.OperandMode.Temp, j); + if (allocator.isProcessed(operand)) { + Interval interval = intervalAt(operand); + assert interval != null : "Could not find interval for operand " + operand; + if (op.id != -1) { + interval = interval.getSplitChildAtOpId(op.id, LIRInstruction.OperandMode.Temp, allocator); + } + + statePut(inputState, interval.location(), interval.splitParent()); + } + } + + // set output operands + n = op.operandCount(LIRInstruction.OperandMode.Output); + for (int j = 0; j < n; j++) { + CiValue operand = op.operandAt(LIRInstruction.OperandMode.Output, j); + if (allocator.isProcessed(operand)) { + Interval interval = intervalAt(operand); + if (op.id != -1) { + interval = interval.getSplitChildAtOpId(op.id, LIRInstruction.OperandMode.Output, allocator); + } + + statePut(inputState, interval.location(), interval.splitParent()); + } + } + } + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/asm/ExceptionInfo.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/asm/ExceptionInfo.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.asm; + +import com.oracle.max.graal.compiler.lir.*; + +public class ExceptionInfo { + + public final int codeOffset; + public final LIRBlock exceptionEdge; + public final int bci; + + public ExceptionInfo(int pcOffset, LIRBlock exceptionEdge, int bci) { + this.codeOffset = pcOffset; + this.exceptionEdge = exceptionEdge; + this.bci = bci; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/asm/TargetMethodAssembler.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/asm/TargetMethodAssembler.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.asm; + +import java.util.*; + +import com.oracle.max.asm.*; +import com.oracle.max.graal.compiler.*; +import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.compiler.lir.*; +import com.oracle.max.graal.compiler.util.*; +import com.sun.cri.ci.*; +import com.sun.cri.ri.*; + +public class TargetMethodAssembler { + public final AbstractAssembler asm; + public final CiTargetMethod targetMethod; + public List exceptionInfoList; + protected int lastSafepointPos; + + public TargetMethodAssembler(AbstractAssembler asm) { + this.asm = asm; + this.targetMethod = new CiTargetMethod(); + } + + public void setFrameSize(int frameSize) { + targetMethod.setFrameSize(frameSize); + } + + public CiTargetMethod.Mark recordMark(Object id, CiTargetMethod.Mark[] references) { + return targetMethod.recordMark(asm.codeBuffer.position(), id, references); + } + + public void blockComment(String s) { + targetMethod.addAnnotation(new CiTargetMethod.CodeComment(asm.codeBuffer.position(), s)); + } + + public CiTargetMethod finishTargetMethod(Object name, RiRuntime runtime, int registerRestoreEpilogueOffset, boolean isStub) { + // Install code, data and frame size + targetMethod.setTargetCode(asm.codeBuffer.close(false), asm.codeBuffer.position()); + targetMethod.setRegisterRestoreEpilogueOffset(registerRestoreEpilogueOffset); + + // Record exception handlers if they exist + if (exceptionInfoList != null) { + for (ExceptionInfo ei : exceptionInfoList) { + int codeOffset = ei.codeOffset; + targetMethod.recordExceptionHandler(codeOffset, -1, 0, ei.exceptionEdge.blockEntryPco, -1, null); + } + } + + if (C1XOptions.PrintMetrics) { + C1XMetrics.TargetMethods++; + C1XMetrics.CodeBytesEmitted += targetMethod.targetCodeSize(); + C1XMetrics.SafepointsEmitted += targetMethod.safepoints.size(); + C1XMetrics.DirectCallSitesEmitted += targetMethod.directCalls.size(); + C1XMetrics.IndirectCallSitesEmitted += targetMethod.indirectCalls.size(); + C1XMetrics.DataPatches += targetMethod.dataReferences.size(); + C1XMetrics.ExceptionHandlersEmitted += targetMethod.exceptionHandlers.size(); + } + + if (C1XOptions.PrintAssembly && !TTY.isSuppressed() && !isStub) { + Util.printSection("Target Method", Util.SECTION_CHARACTER); + TTY.println("Name: " + name); + TTY.println("Frame size: " + targetMethod.frameSize()); + TTY.println("Register size: " + asm.target.arch.registerReferenceMapBitCount); + + if (C1XOptions.PrintCodeBytes) { + Util.printSection("Code", Util.SUB_SECTION_CHARACTER); + TTY.println("Code: %d bytes", targetMethod.targetCodeSize()); + Util.printBytes(0L, targetMethod.targetCode(), 0, targetMethod.targetCodeSize(), C1XOptions.PrintAssemblyBytesPerLine); + } + + Util.printSection("Disassembly", Util.SUB_SECTION_CHARACTER); + String disassembly = runtime.disassemble(targetMethod); + TTY.println(disassembly); + boolean noDis = disassembly == null || disassembly.length() == 0; + + Util.printSection("Safepoints", Util.SUB_SECTION_CHARACTER); + for (CiTargetMethod.Safepoint x : targetMethod.safepoints) { + TTY.println(x.toString()); + if (noDis && x.debugInfo != null) { + TTY.println(CiUtil.indent(x.debugInfo.toString(), " ")); + } + } + + Util.printSection("Direct Call Sites", Util.SUB_SECTION_CHARACTER); + for (CiTargetMethod.Call x : targetMethod.directCalls) { + TTY.println(x.toString()); + if (noDis && x.debugInfo != null) { + TTY.println(CiUtil.indent(x.debugInfo.toString(), " ")); + } + } + + Util.printSection("Indirect Call Sites", Util.SUB_SECTION_CHARACTER); + for (CiTargetMethod.Call x : targetMethod.indirectCalls) { + TTY.println(x.toString()); + if (noDis && x.debugInfo != null) { + TTY.println(CiUtil.indent(x.debugInfo.toString(), " ")); + } + } + + Util.printSection("Data Patches", Util.SUB_SECTION_CHARACTER); + for (CiTargetMethod.DataPatch x : targetMethod.dataReferences) { + TTY.println(x.toString()); + } + + Util.printSection("Marks", Util.SUB_SECTION_CHARACTER); + for (CiTargetMethod.Mark x : targetMethod.marks) { + TTY.println(x.toString()); + } + + Util.printSection("Exception Handlers", Util.SUB_SECTION_CHARACTER); + for (CiTargetMethod.ExceptionHandler x : targetMethod.exceptionHandlers) { + TTY.println(x.toString()); + } + } + + return targetMethod; + } + + public void recordExceptionHandlers(int pcOffset, LIRDebugInfo info) { + if (info != null) { + if (info.exceptionEdge() != null) { + if (exceptionInfoList == null) { + exceptionInfoList = new ArrayList(4); + } + exceptionInfoList.add(new ExceptionInfo(pcOffset, info.exceptionEdge(), info.state.bci)); + } + } + } + + public void recordImplicitException(int pcOffset, LIRDebugInfo info) { + // record an implicit exception point + if (info != null) { + assert lastSafepointPos < pcOffset; + lastSafepointPos = pcOffset; + targetMethod.recordSafepoint(pcOffset, info.debugInfo()); + assert info.exceptionEdge() == null; + } + } + + public void recordDirectCall(int posBefore, int posAfter, Object target, LIRDebugInfo info) { + CiDebugInfo debugInfo = info != null ? info.debugInfo() : null; + assert lastSafepointPos < posAfter; + lastSafepointPos = posAfter; + targetMethod.recordCall(posBefore, target, debugInfo, true); + } + + public void recordIndirectCall(int posBefore, int posAfter, Object target, LIRDebugInfo info) { + CiDebugInfo debugInfo = info != null ? info.debugInfo() : null; + assert lastSafepointPos < posAfter; + lastSafepointPos = posAfter; + targetMethod.recordCall(posBefore, target, debugInfo, false); + } + + public void recordSafepoint(int pos, LIRDebugInfo info) { + // safepoints always need debug info + CiDebugInfo debugInfo = info.debugInfo(); + assert lastSafepointPos < pos; + lastSafepointPos = pos; + targetMethod.recordSafepoint(pos, debugInfo); + } + + public CiAddress recordDataReferenceInCode(CiConstant data) { + assert data != null; + + int pos = asm.codeBuffer.position(); + + if (C1XOptions.TraceRelocation) { + TTY.print("Data reference in code: pos = %d, data = %s", pos, data.toString()); + } + + targetMethod.recordDataReference(pos, data); + return CiAddress.Placeholder; + } + + public int lastSafepointPos() { + return lastSafepointPos; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/debug/BlockPrinter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/debug/BlockPrinter.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.debug; + +import com.oracle.max.graal.compiler.graph.*; +import com.oracle.max.graal.compiler.ir.*; +import com.oracle.max.graal.compiler.schedule.*; +import com.oracle.max.graal.compiler.util.*; +import com.oracle.max.graal.compiler.value.*; +import com.oracle.max.graal.graph.*; + +/** + * Prints a listing for a {@linkplain Merge block}. + */ +public class BlockPrinter implements BlockClosure { + + private final InstructionPrinter ip; + private final boolean cfgOnly; + + public BlockPrinter(IR ir, InstructionPrinter ip, boolean cfgOnly) { + this.ip = ip; + this.cfgOnly = cfgOnly; + } + + public void apply(Block block) { + if (cfgOnly) { + if (block.getInstructions().size() > 0) { + ip.printInstruction((Instruction) block.getInstructions().get(0)); + } else { + ip.out().println("Empty block"); + } + ip.out().println(); + } else { + printBlock(block); + } + } + + public void printBlock(Block block) { + LogStream out = ip.out(); + out.println(); + + ip.printInstructionListingHeader(); + + for (Node i : block.getInstructions()) { + if (i instanceof Instruction) { + ip.printInstructionListing((Instruction) i); + } + } + out.println(); + + } + + private static void printFrameState(FrameState newFrameState, LogStream out) { + int startPosition = out.position(); + if (newFrameState.stackSize() == 0) { + out.print("empty stack"); + } else { + out.print("stack ["); + int i = 0; + while (i < newFrameState.stackSize()) { + if (i > 0) { + out.print(", "); + } + Value value = newFrameState.stackAt(i); + out.print(i + ":" + Util.valueString(value)); + if (value == null) { + i++; + } else { + i += value.kind.sizeInSlots(); + if (value instanceof Phi) { + Phi phi = (Phi) value; + if (phi.operand() != null) { + out.print(" "); + out.print(phi.operand().toString()); + } + } + } + } + out.print(']'); + } + if (newFrameState.locksSize() != 0) { + // print out the lines on the line below this + // one at the same indentation level. + out.println(); + out.fillTo(startPosition, ' '); + out.print("locks ["); + for (int i = 0; i < newFrameState.locksSize(); i++) { + Value value = newFrameState.lockAt(i); + if (i > 0) { + out.print(", "); + } + out.print(i + ":"); + if (value == null) { + // synchronized methods push null on the lock stack + out.print("this"); + } else { + out.print(Util.valueString(value)); + } + } + out.print("]"); + } + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/debug/CFGPrinter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/debug/CFGPrinter.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,636 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.debug; + +import java.io.*; +import java.util.*; + +import com.oracle.max.graal.compiler.*; +import com.oracle.max.graal.compiler.alloc.*; +import com.oracle.max.graal.compiler.alloc.Interval.*; +import com.oracle.max.graal.compiler.graph.*; +import com.oracle.max.graal.compiler.ir.*; +import com.oracle.max.graal.compiler.lir.*; +import com.oracle.max.graal.compiler.lir.LIRInstruction.*; +import com.oracle.max.graal.compiler.schedule.*; +import com.oracle.max.graal.compiler.util.*; +import com.oracle.max.graal.compiler.value.*; +import com.oracle.max.graal.graph.*; +import com.sun.cri.ci.*; +import com.sun.cri.ci.CiAddress.*; +import com.sun.cri.ri.*; + +/** + * Utility for printing the control flow graph of a method being compiled by C1X at various compilation phases. + * The output format matches that produced by HotSpot so that it can then be fed to the + * C1 Visualizer. + */ +public class CFGPrinter { + private static final String COLUMN_END = " <|@"; + private static final String HOVER_START = "<@"; + private static final String HOVER_SEP = "|@"; + private static final String HOVER_END = ">@"; + + private static OutputStream cfgFileStream; + + /** + * Gets the output stream on the file "output.cfg" in the current working directory. + * This stream is first opened if necessary. + * + * @return the output stream to "output.cfg" or {@code null} if there was an error opening this file for writing + */ + public static synchronized OutputStream cfgFileStream() { + if (cfgFileStream == null) { + File cfgFile = new File("output.cfg"); + try { + cfgFileStream = new FileOutputStream(cfgFile); + } catch (FileNotFoundException e) { + TTY.println("WARNING: Could not open " + cfgFile.getAbsolutePath()); + } + } + return cfgFileStream; + } + + private final LogStream out; + private final CiTarget target; + + /** + * Creates a control flow graph printer. + * + * @param os where the output generated via this printer shown be written + * @param target the target architecture description + */ + public CFGPrinter(OutputStream os, CiTarget target) { + out = new LogStream(os); + this.target = target; + } + + /** + * Flushes all buffered output to the stream passed to {@link #CFGPrinter(OutputStream, CiTarget)}. + */ + public void flush() { + out.flush(); + } + + private void begin(String string) { + out.println("begin_" + string); + out.adjustIndentation(2); + } + + private void end(String string) { + out.adjustIndentation(-2); + out.println("end_" + string); + } + + /** + * Prints a compilation timestamp for a given method. + * + * @param method the method for which a timestamp will be printed + */ + public void printCompilation(RiMethod method) { + begin("compilation"); + out.print("name \" ").print(CiUtil.format("%H::%n", method, true)).println('"'); + out.print("method \"").print(CiUtil.format("%f %r %H.%n(%p)", method, true)).println('"'); + out.print("date ").println(System.currentTimeMillis()); + end("compilation"); + } + + /** + * Print the details of a given control flow graph block. + * + * @param block the block to print + * @param successors the successor blocks of {@code block} + * @param handlers the exception handler blocks of {@code block} + * @param printHIR if {@code true} the HIR for each instruction in the block will be printed + * @param printLIR if {@code true} the LIR for each instruction in the block will be printed + */ + void printBlock(Block block, List successors, Block handler, boolean printHIR, boolean printLIR) { + begin("block"); + + out.print("name \"B").print(block.blockID()).println('"'); + out.print("from_bci -1"); + out.print("to_bci -1"); + + out.print("predecessors "); + for (Block pred : block.getPredecessors()) { + out.print("\"B").print(pred.blockID()).print("\" "); + } + out.println(); + + out.print("successors "); + for (Block succ : successors) { + out.print("\"B").print(succ.blockID()).print("\" "); + } + out.println(); + + out.print("xhandlers"); + if (handler != null) { + out.print("\"B").print(handler.blockID()).print("\" "); + } + out.println(); + + out.print("flags "); + out.println(); + + out.print("loop_index ").println(-1); + out.print("loop_depth ").println(-1); + + if (printHIR) { + printHIR(block); + } + + // TODO(tw): Add possibility to print LIR. + //if (printLIR) { + // printLIR(block.lirBlock()); + //} + + end("block"); + } + + /** + * Prints the JVM frame state upon entry to a given block. + * + * @param block the block for which the frame state is to be printed + */ + /*private void printState(Block block) { + begin("states"); + + FrameState state = block.stateBefore(); + if (state == null) { + return; + } + int stackSize = state.stackSize(); + if (stackSize > 0) { + begin("stack"); + out.print("size ").println(stackSize); + out.print("method \"").print(CiUtil.toLocation(C1XCompilation.compilation().method, state.bci)).println('"'); + + int i = 0; + while (i < stackSize) { + Value value = state.stackAt(i); + out.disableIndentation(); + out.print(block.stateString(i, value)); + printOperand(value); + out.println(); + out.enableIndentation(); + if (value == null) { + i++; + } else { + i += value.kind.sizeInSlots(); + } + } + end("stack"); + } + + if (state.locksSize() > 0) { + begin("locks"); + out.print("size ").println(state.locksSize()); + out.print("method \"").print(CiUtil.toLocation(C1XCompilation.compilation().method, state.bci)).println('"'); + + for (int i = 0; i < state.locksSize(); ++i) { + Value value = state.lockAt(i); + out.disableIndentation(); + out.print(block.stateString(i, value)); + printOperand(value); + out.println(); + out.enableIndentation(); + } + end("locks"); + } + + begin("locals"); + out.print("size ").println(state.localsSize()); + out.print("method \"").print(CiUtil.toLocation(C1XCompilation.compilation().method, state.bci)).println('"'); + int i = 0; + while (i < state.localsSize()) { + Value value = state.localAt(i); + if (value != null) { + out.disableIndentation(); + out.print(block.stateString(i, value)); + printOperand(value); + out.println(); + out.enableIndentation(); + // also ignore illegal HiWords + i += value.isIllegal() ? 1 : value.kind.sizeInSlots(); + } else { + i++; + } + } + end("locals"); + end("states"); + }*/ + + /** + * Formats a given {@linkplain FrameState JVM frame state} as a multi line string. + */ + private String stateToString(FrameState state, CFGOperandFormatter operandFmt) { + if (state == null) { + return null; + } + + StringBuilder buf = new StringBuilder(); + buf.append(CiUtil.toLocation(C1XCompilation.compilation().method, state.bci)); + buf.append('\n'); + if (state.stackSize() > 0) { + int i = 0; + buf.append("stack: "); + while (i < state.stackSize()) { + if (i == 0) { + buf.append(' '); + } + Value value = state.stackAt(i); + buf.append(stateValueToString(value, operandFmt)).append(' '); + i++; + } + buf.append("\n"); + } + + if (state.locksSize() > 0) { + buf.append("locks: "); + for (int i = 0; i < state.locksSize(); ++i) { + if (i == 0) { + buf.append(' '); + } + Value value = state.lockAt(i); + buf.append(stateValueToString(value, operandFmt)).append(' '); + } + buf.append("\n"); + } + + buf.append("locals: "); + int i = 0; + while (i < state.localsSize()) { + if (i == 0) { + buf.append(' '); + } + Value value = state.localAt(i); + buf.append(stateValueToString(value, operandFmt)).append(' '); + i++; + } + buf.append("\n"); + return buf.toString(); + } + + private String stateValueToString(Value value, OperandFormatter operandFmt) { + if (operandFmt == null) { + return Util.valueString(value); + } + if (value == null) { + return "-"; + } + return operandFmt.format(value.operand()); + } + + private String stateValueToString(CiValue value, OperandFormatter operandFmt) { + if (value == null) { + return "-"; + } + return operandFmt.format(value); + } + + /** + * Formats a given {@linkplain FrameState JVM frame state} as a multi line string. + */ + private String debugInfoToString(CiDebugInfo info, CFGOperandFormatter operandFmt) { + if (info == null) { + return null; + } + StringBuilder sb = new StringBuilder(); + + + if (info.hasRegisterRefMap()) { + sb.append("reg-ref-map:"); + C1XCompilation compilation = C1XCompilation.compilation(); + CiArchitecture arch = compilation == null ? null : compilation.target.arch; + for (int reg = info.registerRefMap.nextSetBit(0); reg >= 0; reg = info.registerRefMap.nextSetBit(reg + 1)) { + sb.append(' ').append(arch == null ? "reg" + reg : arch.registers[reg]); + } + sb.append("\n"); + } + if (info.hasStackRefMap()) { + sb.append("frame-ref-map:"); + CiBitMap bm = info.frameRefMap; + for (int i = bm.nextSetBit(0); i >= 0; i = bm.nextSetBit(i + 1)) { + sb.append(' ').append(CiStackSlot.get(CiKind.Object, i)); + } + sb.append("\n"); + } + if (info.codePos != null) { + sb.append(stateToString(info.codePos, operandFmt)); + } + return sb.toString(); + } + + /** + * Formats a given {@linkplain FrameState JVM frame state} as a multi line string. + */ + private String stateToString(CiCodePos codePos, CFGOperandFormatter operandFmt) { + if (codePos == null) { + return null; + } + + StringBuilder buf = new StringBuilder(); + + do { + buf.append(CiUtil.toLocation(codePos.method, codePos.bci)); + buf.append('\n'); + if (codePos instanceof CiFrame) { + CiFrame frame = (CiFrame) codePos; + if (frame.numStack > 0) { + int i = 0; + buf.append("stack: "); + while (i < frame.numStack) { + if (i == 0) { + buf.append(' '); + } + CiValue value = frame.getStackValue(i); + buf.append(stateValueToString(value, operandFmt)).append(' '); + i++; + } + buf.append("\n"); + } + + if (frame.numLocks > 0) { + buf.append("locks: "); + for (int i = 0; i < frame.numLocks; ++i) { + if (i == 0) { + buf.append(' '); + } + CiValue value = frame.getLockValue(i); + buf.append(stateValueToString(value, operandFmt)).append(' '); + } + buf.append("\n"); + } + + buf.append("locals: "); + int i = 0; + while (i < frame.numLocals) { + if (i == 0) { + buf.append(' '); + } + CiValue value = frame.getLocalValue(i); + buf.append(stateValueToString(value, operandFmt)).append(' '); + i++; + } + buf.append("\n"); + } + codePos = codePos.caller; + } while (codePos != null); + return buf.toString(); + } + + /** + * Prints the HIR for each instruction in a given block. + * + * @param block + */ + private void printHIR(Block block) { + begin("IR"); + out.println("HIR"); + out.disableIndentation(); + for (Node i : block.getInstructions()) { + if (i instanceof Instruction) { + printInstructionHIR((Instruction) i); + } + } + out.enableIndentation(); + end("IR"); + } + + /** + * Formats LIR operands as expected by the C1 Visualizer. + */ + public static class CFGOperandFormatter extends OperandFormatter { + /** + * The textual delimiters used for an operand depend on the context in which it is being + * printed. When printed as part of a frame state or as the result operand in a HIR node listing, + * it is enclosed in double-quotes (i.e. {@code "}'s). + */ + public final boolean asStateOrHIROperandResult; + + public CFGOperandFormatter(boolean asStateOrHIROperandResult) { + this.asStateOrHIROperandResult = asStateOrHIROperandResult; + } + + @Override + public String format(CiValue operand) { + if (operand.isLegal()) { + String op; + if (operand.isVariableOrRegister() || operand.isStackSlot()) { + op = operand.name(); + } else if (operand.isConstant()) { + CiConstant constant = (CiConstant) operand; + op = operand.kind.javaName + ":" + operand.kind.format(constant.boxedValue()); + } else if (operand.isAddress()) { + CiAddress address = (CiAddress) operand; + op = "Base:" + format(address.base); + if (!address.index.isIllegal()) { + op += " Index:" + format(address.index); + } + if (address.scale != Scale.Times1) { + op += " * " + address.scale.value; + } + op += " Disp:" + address.displacement; + } else { + assert operand.isIllegal(); + op = "-"; + } + if (operand.kind != CiKind.Illegal) { + op += "|" + operand.kind.typeChar; + } + if (asStateOrHIROperandResult) { + op = " \"" + op.replace('"', '\'') + "\" "; + } + return op; + } + return ""; + } + } + + /** + * Prints the LIR for each instruction in a given block. + * + * @param block the block to print + */ + private void printLIR(LIRBlock block) { + LIRList lir = block.lir(); + if (lir != null) { + begin("IR"); + out.println("LIR"); + for (int i = 0; i < lir.length(); i++) { + LIRInstruction inst = lir.at(i); + out.printf("nr %4d ", inst.id).print(COLUMN_END); + + if (inst.info != null) { + int level = out.indentationLevel(); + out.adjustIndentation(-level); + String state; + if (inst.info.debugInfo != null) { + // Use register-allocator output if available + state = debugInfoToString(inst.info.debugInfo, new CFGOperandFormatter(false)); + } else { + state = stateToString(inst.info.state, new CFGOperandFormatter(false)); + } + if (state != null) { + out.print(" st ").print(HOVER_START).print("st").print(HOVER_SEP).print(state).print(HOVER_END).print(COLUMN_END); + } + out.adjustIndentation(level); + } + + out.print(" instruction ").print(inst.toString(new CFGOperandFormatter(false))).print(COLUMN_END); + out.println(COLUMN_END); + } + end("IR"); + } + } + + private void printOperand(Value i) { + if (i != null && i.operand().isLegal()) { + out.print(new CFGOperandFormatter(true).format(i.operand())); + } + } + + /** + * Prints the HIR for a given instruction. + * + * @param i the instruction for which HIR will be printed + */ + private void printInstructionHIR(Instruction i) { + out.print("bci ").print(-1).println(COLUMN_END); + if (i.operand().isLegal()) { + out.print("result ").print(new CFGOperandFormatter(false).format(i.operand())).println(COLUMN_END); + } + out.print("tid ").print(i).println(COLUMN_END); + + String state = stateToString(i.stateAfter(), null); + if (state != null) { + out.print("st ").print(HOVER_START).print("st").print(HOVER_SEP).print(state).print(HOVER_END).println(COLUMN_END); + } + + out.print("instruction "); + i.print(out); + out.print(COLUMN_END).print(' ').println(COLUMN_END); + } + + /** + * Prints the control flow graph denoted by a given block map. + * + * @param blockMap a data structure describing the blocks in a method and how they are connected + * @param codeSize the bytecode size of the method from which {@code blockMap} was produced + * @param label a label describing the compilation phase that produced the control flow graph + * @param printHIR if {@code true} the HIR for each instruction in the block will be printed + * @param printLIR if {@code true} the LIR for each instruction in the block will be printed + */ + public void printCFG(RiMethod method, BlockMap blockMap, int codeSize, String label, boolean printHIR, boolean printLIR) { + begin("cfg"); + out.print("name \"").print(label).println('"'); + for (BlockMap.Block block : blockMap.blocks) { + begin("block"); + blockMap.printBlock(block, out); + end("block"); + } + end("cfg"); + } + + /** + * Prints the control flow graph rooted at a given block. + * + * @param startBlock the entry block of the control flow graph to be printed + * @param label a label describing the compilation phase that produced the control flow graph + * @param printHIR if {@code true} the HIR for each instruction in the block will be printed + * @param printLIR if {@code true} the LIR for each instruction in the block will be printed + */ + public void printCFG(Block startBlock, String label, final boolean printHIR, final boolean printLIR) { + begin("cfg"); + out.print("name \"").print(label).println('"'); + startBlock.iteratePreOrder(new BlockClosure() { + public void apply(Block block) { + List successors = block.getSuccessors(); + printBlock(block, successors, null, printHIR, printLIR); + } + }); + end("cfg"); + } + + public void printIntervals(LinearScan allocator, Interval[] intervals, String name) { + begin("intervals"); + out.println(String.format("name \"%s\"", name)); + + for (Interval interval : intervals) { + if (interval != null) { + printInterval(allocator, interval); + } + } + + end("intervals"); + } + + private void printInterval(LinearScan allocator, Interval interval) { + out.printf("%d %s ", interval.operandNumber, (interval.operand.isRegister() ? "fixed" : interval.kind().name())); + if (interval.operand.isRegister()) { + out.printf("\"[%s|%c]\"", interval.operand.name(), interval.operand.kind.typeChar); + } else { + if (interval.location() != null) { + out.printf("\"[%s|%c]\"", interval.location().name(), interval.location().kind.typeChar); + } + } + + Interval hint = interval.locationHint(false, allocator); + out.printf("%d %d ", interval.splitParent().operandNumber, hint != null ? hint.operandNumber : -1); + + // print ranges + Range cur = interval.first(); + while (cur != Range.EndMarker) { + out.printf("[%d, %d[", cur.from, cur.to); + cur = cur.next; + assert cur != null : "range list not closed with range sentinel"; + } + + // print use positions + int prev = 0; + UsePosList usePosList = interval.usePosList(); + for (int i = usePosList.size() - 1; i >= 0; --i) { + assert prev < usePosList.usePos(i) : "use positions not sorted"; + out.printf("%d %s ", usePosList.usePos(i), usePosList.registerPriority(i)); + prev = usePosList.usePos(i); + } + + out.printf(" \"%s\"", interval.spillState()); + out.println(); + } + + public void printMachineCode(String code, String label) { + if (code.length() == 0) { + return; + } + if (label != null) { + begin("cfg"); + out.print("name \"").print(label).println('"'); + end("cfg"); + } + begin("nmethod"); + out.print(code); + out.println(" <|@"); + end("nmethod"); + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/debug/CFGPrinterObserver.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/debug/CFGPrinterObserver.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.debug; + +import java.io.*; + +import com.oracle.max.graal.compiler.*; +import com.oracle.max.graal.compiler.observer.*; +import com.sun.cri.ri.*; + +/** + * Observes compilation events and uses {@link CFGPrinter} to produce a control flow graph for the C1 Visualizer. + * + * @author Peter Hofer + */ +public class CFGPrinterObserver implements CompilationObserver { + + private C1XCompilation currentCompilation; + private CFGPrinter cfgPrinter; + private ByteArrayOutputStream buffer = null; + private final OutputStream stream; + + public CFGPrinterObserver() { + this(CFGPrinter.cfgFileStream()); + } + + public CFGPrinterObserver(OutputStream stream) { + this.stream = stream; + } + + @Override + public void compilationStarted(CompilationEvent event) { + // Supports only one compilation at the same time + assert currentCompilation == null; + + currentCompilation = event.getCompilation(); + if (buffer == null) { + buffer = new ByteArrayOutputStream(); + } + cfgPrinter = new CFGPrinter(buffer, currentCompilation.target); + cfgPrinter.printCompilation(currentCompilation.method); + } + + @Override + public void compilationEvent(CompilationEvent event) { + assert currentCompilation == event.getCompilation(); + + String label = event.getLabel(); + + if (event.getAllocator() != null && event.getIntervals() != null) { + cfgPrinter.printIntervals(event.getAllocator(), event.getIntervals(), label); + } + + boolean cfgprinted = false; + + if (event.getBlockMap() != null && event.getCodeSize() >= 0) { + cfgPrinter.printCFG(event.getMethod(), event.getBlockMap(), event.getCodeSize(), label, event.isHIRValid(), event.isLIRValid()); + cfgprinted = true; + } + + // TODO fix that when schedule is here (startBlock : Instruction->Block) + /*if (event.getStartBlock() != null) { + cfgPrinter.printCFG((BlockBegin) event.getStartBlock(), label, event.isHIRValid(), event.isLIRValid()); + cfgprinted = true; + }*/ + + if (event.getTargetMethod() != null) { + if (cfgprinted) { + // Avoid duplicate "cfg" section + label = null; + } + + RiRuntime runtime = event.getCompilation().runtime; + cfgPrinter.printMachineCode(runtime.disassemble(event.getTargetMethod()), label); + } + } + + @Override + public void compilationFinished(CompilationEvent event) { + assert currentCompilation == event.getCompilation(); + + cfgPrinter.flush(); + + if (stream != null) { + synchronized (stream) { + try { + stream.write(buffer.toByteArray()); + stream.flush(); + } catch (IOException e) { + TTY.println("WARNING: Error writing CFGPrinter output for %s: %s", event.getMethod(), e); + } + } + } + + buffer.reset(); + cfgPrinter = null; + currentCompilation = null; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/debug/GraphvizPrinterObserver.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/debug/GraphvizPrinterObserver.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.debug; + +import java.io.*; +import java.util.regex.*; + +import com.oracle.max.graal.compiler.*; +import com.oracle.max.graal.compiler.ir.*; +import com.oracle.max.graal.compiler.observer.*; +import com.oracle.max.graal.compiler.value.*; +import com.oracle.max.graal.graph.*; +import com.oracle.max.graal.graphviz.*; + +/** + * Observes compilation events and uses {@link GraphvizPrinter} to produce a control flow graph in the DOT language + * which can be visualized with Graphviz. + * + * @author Peter Hofer + */ +public class GraphvizPrinterObserver implements CompilationObserver { + + private static final Pattern INVALID_CHAR = Pattern.compile("[^A-Za-z0-9_.-]"); + + private final boolean pdf; + private int n; + + public GraphvizPrinterObserver(boolean pdf) { + this.pdf = pdf; + } + + public void compilationStarted(CompilationEvent event) { + n = 0; + } + + public void compilationFinished(CompilationEvent event) { + } + + public void compilationEvent(CompilationEvent event) { + if (event.getGraph() != null && !TTY.isSuppressed()) { + Graph graph = event.getGraph(); + + String name = event.getMethod().holder().name(); + name = name.substring(1, name.length() - 1).replace('/', '.'); + name = name + "." + event.getMethod().name(); + + String filename = name + "_" + (n++) + "_" + event.getLabel(); + filename = INVALID_CHAR.matcher(filename).replaceAll("_"); + + OutputStream out = null; + try { + if (pdf) { + ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + printGraph(graph, name, buffer); + + out = new FileOutputStream(filename + ".pdf"); + GraphvizRunner.process(GraphvizRunner.DOT_LAYOUT, new ByteArrayInputStream(buffer.toByteArray()), out, "pdf"); + } else { + out = new FileOutputStream(filename + ".gv"); + + printGraph(graph, name, out); + } + } catch (IOException e) { + e.printStackTrace(); + } finally { + if (out != null) { + try { + out.close(); + } catch (IOException e) { + } + } + } + } + } + + private static void printGraph(Graph graph, String name, OutputStream buffer) { + GraphvizPrinter printer = new GraphvizPrinter(buffer); + if (C1XOptions.OmitDOTFrameStates) { + printer.addOmittedClass(FrameState.class); + } + printer.addClassColor(StartNode.class, "snow3"); + printer.addClassColor(LoopBegin.class, "skyblue"); + printer.addClassColor(LoopEnd.class, "skyblue3"); + printer.addClassColor(Unwind.class, "red"); + printer.addClassColor(Return.class, "indianred1"); + printer.begin(name); + printer.print(graph, true); + printer.end(); + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/debug/IdealGraphPrinter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/debug/IdealGraphPrinter.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,277 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.debug; + +import java.io.*; +import java.util.*; +import java.util.Map.*; + +import com.oracle.max.graal.compiler.ir.*; +import com.oracle.max.graal.compiler.schedule.*; +import com.oracle.max.graal.graph.*; + +/** + * Generates a representation of {@link Graph Graphs} that can be visualized and inspected with the Ideal Graph Visualizer. + */ +public class IdealGraphPrinter { + + private static class Edge { + final int from; + final int to; + final int fromIndex; + final int toIndex; + + Edge(int from, int fromIndex, int to, int toIndex) { + this.from = from; + this.fromIndex = fromIndex; + this.to = to; + this.toIndex = toIndex; + } + } + + private final HashSet> omittedClasses = new HashSet>(); + private final PrintStream stream; + private final List noBlockNodes = new LinkedList(); + + /** + * Creates a new {@link IdealGraphPrinter} that writes to the specified output stream. + */ + public IdealGraphPrinter(OutputStream stream) { + this.stream = new PrintStream(stream); + } + + /** + * Adds a node class that is omitted in the output. + */ + public void addOmittedClass(Class clazz) { + omittedClasses.add(clazz); + } + + /** + * Flushes any buffered output. + */ + public void flush() { + stream.flush(); + } + + /** + * Starts a new graph document. + */ + public void begin() { + stream.println(""); + } + + /** + * Starts a new group of graphs with the given name, short name and method byte code index (BCI) as properties. + */ + public void beginGroup(String name, String shortName, int bci) { + stream.println(""); + stream.printf("

%s

%n", escape(name)); + stream.printf(" %n", escape(name), escape(shortName), bci); + } + + /** + * Ends the current group. + */ + public void endGroup() { + stream.println(""); + } + + /** + * Finishes the graph document and flushes the output stream. + */ + public void end() { + stream.println(""); + flush(); + } + + /** + * Prints an entire {@link Graph} with the specified title, optionally using short names for nodes. + */ + public void print(Graph graph, String title, boolean shortNames) { + stream.printf(" %n", escape(title)); + + Schedule schedule = null; + try { + schedule = new Schedule(graph); + } catch (Throwable t) { + // nothing to do here... + } + + stream.println(" "); + List edges = printNodes(graph.getNodes(), shortNames, schedule == null ? null : schedule.getNodeToBlock()); + stream.println(" "); + + stream.println(" "); + for (Edge edge : edges) { + printEdge(edge); + } + stream.println(" "); + + stream.println(" "); + if (schedule != null) { + for (Block block : schedule.getBlocks()) { + printBlock(graph, block); + } + printNoBlock(); + } + stream.println(" "); + + stream.println(" "); + } + + private List printNodes(Collection nodes, boolean shortNames, NodeMap nodeToBlock) { + ArrayList edges = new ArrayList(); + + for (Node node : nodes) { + if (node == Node.Null || omittedClasses.contains(node.getClass())) { + continue; + } + + stream.printf(" %n", node.id()); + stream.printf("

%d

%n", node.id()); + + Map props = node.getDebugProperties(); + if (!props.containsKey("name") || props.get("name").toString().trim().length() == 0) { + String name; + if (shortNames) { + name = node.shortName(); + } else { + name = node.toString(); + } + stream.printf("

%s

%n", escape(name)); + } + if (nodeToBlock != null) { + Block block = nodeToBlock.get(node); + if (block != null) { + stream.printf("

%d

%n", block.blockID()); + } else { + stream.printf("

noBlock

%n"); + noBlockNodes.add(node); + } + } + for (Entry entry : props.entrySet()) { + String key = entry.getKey().toString(); + String value = entry.getValue().toString(); + stream.printf("

%s

%n", escape(key), escape(value)); + } + + stream.println("
"); + + // successors + int fromIndex = 0; + for (Node successor : node.successors()) { + if (successor != Node.Null && !omittedClasses.contains(successor.getClass())) { + edges.add(new Edge(node.id(), fromIndex, successor.id(), 0)); + } + fromIndex++; + } + + // inputs + int toIndex = 1; + for (Node input : node.inputs()) { + if (input != Node.Null && !omittedClasses.contains(input.getClass())) { + edges.add(new Edge(input.id(), input.successors().size(), node.id(), toIndex)); + } + toIndex++; + } + } + + return edges; + } + + private void printEdge(Edge edge) { + stream.printf(" %n", edge.from, edge.fromIndex, edge.to, edge.toIndex); + } + + private void printBlock(Graph graph, Block block) { + stream.printf(" %n", block.blockID()); + stream.printf(" %n"); + for (Block sux : block.getSuccessors()) { + if (sux.firstNode() instanceof LoopBegin && block.lastNode() instanceof LoopEnd) { + // Skip back edges. + } else { + stream.printf(" %n", sux.blockID()); + } + } + stream.printf(" %n"); + stream.printf(" %n"); + + ArrayList nodes = new ArrayList(block.getInstructions()); + // if this is the first block: add all locals to this block + if (nodes.get(0) == graph.start()) { + for (Node node : graph.getNodes()) { + if (node instanceof Local) { + nodes.add(node); + } + } + } + // add all framestates and phis to their blocks + for (Node node : block.getInstructions()) { + if (node instanceof Instruction && ((Instruction) node).stateAfter() != null) { + nodes.add(((Instruction) node).stateAfter()); + } + if (node instanceof Merge) { + Merge merge = (Merge) node; + if (merge.stateBefore() != null) { + nodes.add(merge.stateBefore()); + } + for (Node usage : merge.usages()) { + if (usage instanceof Phi) { + nodes.add(usage); + } + } + } + } + + for (Node node : nodes) { + if (!omittedClasses.contains(node.getClass())) { + stream.printf(" %n", node.id()); + } + } + stream.printf(" %n"); + stream.printf(" %n", block.blockID()); + } + + private void printNoBlock() { + if (!noBlockNodes.isEmpty()) { + stream.printf(" %n"); + stream.printf(" %n"); + for (Node node : noBlockNodes) { + stream.printf(" %n", node.id()); + } + stream.printf(" %n"); + stream.printf(" %n"); + } + } + + private String escape(String s) { + s = s.replace("&", "&"); + s = s.replace("<", "<"); + s = s.replace(">", ">"); + s = s.replace("\"", """); + s = s.replace("'", "'"); + return s; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/debug/IdealGraphPrinterObserver.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/debug/IdealGraphPrinterObserver.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.debug; + +import java.io.*; +import java.net.*; +import java.util.regex.*; + +import com.oracle.max.graal.compiler.*; +import com.oracle.max.graal.compiler.observer.*; +import com.oracle.max.graal.compiler.value.*; +import com.oracle.max.graal.graph.*; + +/** + * Observes compilation events and uses {@link IdealGraphPrinter} to generate a graph representation that can be + * inspected with the Ideal Graph Visualizer. + * + * @author Peter Hofer + */ +public class IdealGraphPrinterObserver implements CompilationObserver { + + private static final Pattern INVALID_CHAR = Pattern.compile("[^A-Za-z0-9_.-]"); + + private final String host; + private final int port; + + private IdealGraphPrinter printer; + private OutputStream stream; + private Socket socket; + + /** + * Creates a new {@link IdealGraphPrinterObserver} that writes output to a file named after the compiled method. + */ + public IdealGraphPrinterObserver() { + this(null, -1); + } + + /** + * Creates a new {@link IdealGraphPrinterObserver} that sends output to a remove IdealGraphVisualizer instance. + */ + public IdealGraphPrinterObserver(String host, int port) { + this.host = host; + this.port = port; + } + + @Override + public void compilationStarted(CompilationEvent event) { + assert (stream == null && printer == null); + + if (!TTY.isSuppressed()) { + String name = event.getMethod().holder().name(); + name = name.substring(1, name.length() - 1).replace('/', '.'); + name = name + "." + event.getMethod().name(); + + if (host != null) { + openNetworkPrinter(name); + } else { + openFilePrinter(name); + } + } + } + + private void openFilePrinter(String name) { + String filename = name + ".igv.xml"; + filename = INVALID_CHAR.matcher(filename).replaceAll("_"); + + try { + stream = new FileOutputStream(filename); + printer = new IdealGraphPrinter(stream); + if (C1XOptions.OmitDOTFrameStates) { + printer.addOmittedClass(FrameState.class); + } + printer.begin(); + printer.beginGroup(name, name, -1); + } catch (IOException e) { + e.printStackTrace(); + } + } + + private void openNetworkPrinter(String name) { + try { + socket = new Socket(host, port); + if (socket.getInputStream().read() == 'y') { + stream = socket.getOutputStream(); + } else { + // server currently does not accept any input + socket.close(); + socket = null; + return; + } + + printer = new IdealGraphPrinter(stream); + if (C1XOptions.OmitDOTFrameStates) { + printer.addOmittedClass(FrameState.class); + } + printer.begin(); + printer.beginGroup(name, name, -1); + printer.flush(); + if (socket.getInputStream().read() != 'y') { + // server declines input for this method + socket.close(); + socket = null; + stream = null; + printer = null; + } + } catch (IOException e) { + e.printStackTrace(); + + if (socket != null) { + try { + socket.close(); + } catch (IOException ioe) { + } + socket = null; + } + stream = null; + printer = null; + } + } + + @Override + public void compilationEvent(CompilationEvent event) { + if (printer != null && event.getGraph() != null) { + Graph graph = event.getGraph(); + printer.print(graph, event.getLabel(), true); + } + } + + @Override + public void compilationFinished(CompilationEvent event) { + if (printer != null) { + try { + printer.endGroup(); + printer.end(); + + if (socket != null) { + socket.close(); // also closes stream + } else { + stream.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } finally { + printer = null; + stream = null; + socket = null; + } + } + } + +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/debug/InstructionPrinter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/debug/InstructionPrinter.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.debug; + +import static com.oracle.max.graal.compiler.debug.InstructionPrinter.InstructionLineColumn.*; + +import com.oracle.max.graal.compiler.ir.*; + +/** + * A {@link ValueVisitor} for {@linkplain #printInstruction(Value) printing} + * an {@link Instruction} as an expression or statement. + * + * @author Doug Simon + */ +public class InstructionPrinter { + + + /** + * The columns printed in a tabulated instruction + * {@linkplain InstructionPrinter#printInstructionListing(Value) listing}. + */ + public enum InstructionLineColumn { + /** + * The instruction's bytecode index. + */ + BCI(2, "bci"), + + /** + * The instruction's use count. + */ + USE(7, "use"), + + /** + * The instruction as a {@linkplain com.oracle.max.graal.compiler.util.Util#valueString(com.oracle.max.graal.compiler.ir.Value) value}. + */ + VALUE(12, "tid"), + + /** + * The instruction formatted as an expression or statement. + */ + INSTRUCTION(19, "instr"), + + END(60, ""); + + final int position; + final String label; + + private InstructionLineColumn(int position, String label) { + this.position = position; + this.label = label; + } + + /** + * Prints this column's label to a given stream after padding the stream with '_' characters + * until its {@linkplain LogStream#position() position} is equal to this column's position. + * @param out the print stream + */ + public void printLabel(LogStream out) { + out.fillTo(position + out.indentationLevel(), '_'); + out.print(label); + } + + /** + * Prints space characters to a given stream until its {@linkplain LogStream#position() position} + * is equal to this column's position. + * @param out the print stream + */ + public void advance(LogStream out) { + out.fillTo(position + out.indentationLevel(), ' '); + } + } + + private final LogStream out; + + public InstructionPrinter(LogStream out) { + this.out = out; + } + + public LogStream out() { + return out; + } + + /** + * Prints a given instruction as an expression or statement. + * + * @param instruction the instruction to print + */ + public void printInstruction(Value instruction) { + instruction.print(out); + } + + + /** + * Prints a header for the tabulated data printed by {@link #printInstructionListing(Value)}. + */ + public void printInstructionListingHeader() { + BCI.printLabel(out); + USE.printLabel(out); + VALUE.printLabel(out); + INSTRUCTION.printLabel(out); + END.printLabel(out); + out.println(); + } + + /** + * Prints an instruction listing on one line. The instruction listing is composed of the + * columns specified by {@link InstructionLineColumn}. + * + * @param instruction the instruction to print + */ + public void printInstructionListing(Value instruction) { + int indentation = out.indentationLevel(); + out.fillTo(BCI.position + indentation, ' '). + print(0). + fillTo(USE.position + indentation, ' '). + print("0"). + fillTo(VALUE.position + indentation, ' '). + print(instruction). + fillTo(INSTRUCTION.position + indentation, ' '); + printInstruction(instruction); + String flags = instruction.flagsToString(); + if (!flags.isEmpty()) { + out.print(" [flags: " + flags + "]"); + } + if (instruction instanceof StateSplit) { + out.print(" [state: " + ((StateSplit) instruction).stateAfter() + "]"); + } + out.println(); + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/debug/LogStream.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/debug/LogStream.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,493 @@ +/* + * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.debug; + +import java.io.*; + +import com.oracle.max.graal.compiler.ir.*; +import com.oracle.max.graal.compiler.util.*; + +/** + * A utility for printing compiler debug and informational output to an output stream. + * + * A {@link LogStream} instance maintains an internal buffer that is flushed to the underlying + * output stream every time one of the {@code println} methods is invoked, or a newline character + * ({@code '\n'}) is written. + * + * All of the {@code print} and {@code println} methods return the {code LogStream} instance + * on which they were invoked. This allows chaining of these calls to mitigate use of String + * concatenation by the caller. + * + * A {@code LogStream} maintains a current {@linkplain #indentationLevel() indentation} level. + * Each line of output written to this stream has {@code n} spaces prefixed to it where + * {@code n} is the value that would be returned by {@link #indentationLevel()} when the first + * character of a new line is written. + * + * A {@code LogStream} maintains a current {@linkplain #position() position} for the current + * line being written. This position can be advanced to a specified position by + * {@linkplain #fillTo(int, char) filling} this stream with a given character. + * + * @author Doug Simon + */ +public class LogStream { + + /** + * Null output stream that simply swallows any output sent to it. + */ + public static final LogStream SINK = new LogStream(); + + private LogStream() { + this.ps = null; + this.lineBuffer = null; + } + + /** + * The output stream to which this log stream writes. + */ + private final PrintStream ps; + + private final StringBuilder lineBuffer; + private int indentationLevel; + private char indentation = ' '; + private boolean indentationDisabled; + + /** + * The system dependent line separator. + */ + public static final String LINE_SEPARATOR = System.getProperty("line.separator"); + + /** + * Creates a new log stream. + * + * @param os the underlying output stream to which prints are sent + */ + public LogStream(OutputStream os) { + ps = os instanceof PrintStream ? (PrintStream) os : new PrintStream(os); + lineBuffer = new StringBuilder(100); + } + + /** + * Creates a new log stream that shares the same {@linkplain #ps output stream} as a given {@link LogStream}. + * + * @param log a LogStream whose output stream is shared with this one + */ + public LogStream(LogStream log) { + ps = log.ps; + lineBuffer = new StringBuilder(100); + } + + /** + * Prepends {@link #indentation} to the current output line until its write position is equal to the + * current {@linkplain #indentationLevel()} level. + */ + private void indent() { + if (ps != null) { + if (!indentationDisabled && indentationLevel != 0) { + while (lineBuffer.length() < indentationLevel) { + lineBuffer.append(indentation); + } + } + } + } + + private LogStream flushLine(boolean withNewline) { + if (ps != null) { + if (withNewline) { + lineBuffer.append(LINE_SEPARATOR); + } else { + assert lineBuffer.indexOf(LINE_SEPARATOR, lineBuffer.length() - LINE_SEPARATOR.length()) != -1; + } + ps.print(lineBuffer.toString()); + ps.flush(); + lineBuffer.setLength(0); + } + return this; + } + + /** + * Flushes the stream. This is done by terminating the current line if it is not at position 0 + * and then flushing the underlying output stream. + */ + public void flush() { + if (ps != null) { + if (lineBuffer.length() != 0) { + flushLine(true); + } + ps.flush(); + } + } + + /** + * Gets the current column position of this log stream. + * + * @return the current column position of this log stream + */ + public int position() { + return lineBuffer == null ? 0 : lineBuffer.length(); + + } + + /** + * Gets the current indentation level for this log stream. + * + * @return the current indentation level for this log stream. + */ + public int indentationLevel() { + return indentationLevel; + } + + /** + * Adjusts the current indentation level of this log stream. + * + * @param delta + */ + public void adjustIndentation(int delta) { + if (delta < 0) { + indentationLevel = Math.max(0, indentationLevel + delta); + } else { + indentationLevel += delta; + } + } + + /** + * Gets the current indentation character of this log stream. + */ + public char indentation() { + return indentation; + } + + public void disableIndentation() { + indentationDisabled = true; + } + + public void enableIndentation() { + indentationDisabled = false; + } + + /** + * Sets the character used for indentation. + */ + public void setIndentation(char c) { + indentation = c; + } + + /** + * Advances this stream's {@linkplain #position() position} to a given position by + * repeatedly appending a given character as necessary. + * + * @param position the position to which this stream's position will be advanced + * @param filler the character used to pad the stream + */ + public LogStream fillTo(int position, char filler) { + if (ps != null) { + indent(); + while (lineBuffer.length() < position) { + lineBuffer.append(filler); + } + } + return this; + } + + /** + * Writes a boolean value to this stream as {@code "true"} or {@code "false"}. + * + * @param b the value to be printed + * @return this {@link LogStream} instance + */ + public LogStream print(boolean b) { + if (ps != null) { + indent(); + lineBuffer.append(b); + } + return this; + } + + /** + * Writes a boolean value to this stream followed by a {@linkplain #LINE_SEPARATOR line separator}. + * + * @param b the value to be printed + * @return this {@link LogStream} instance + */ + public LogStream println(boolean b) { + if (ps != null) { + indent(); + lineBuffer.append(b); + return flushLine(true); + } + return this; + } + + /** + * Writes a character value to this stream. + * + * @param c the value to be printed + * @return this {@link LogStream} instance + */ + public LogStream print(char c) { + if (ps != null) { + indent(); + lineBuffer.append(c); + if (c == '\n') { + if (lineBuffer.indexOf(LINE_SEPARATOR, lineBuffer.length() - LINE_SEPARATOR.length()) != -1) { + flushLine(false); + } + } + } + return this; + } + + /** + * Writes a character value to this stream followed by a {@linkplain #LINE_SEPARATOR line separator}. + * + * @param c the value to be printed + * @return this {@link LogStream} instance + */ + public LogStream println(char c) { + if (ps != null) { + indent(); + lineBuffer.append(c); + flushLine(true); + } + return this; + } + + /** + * Prints an int value. + * + * @param i the value to be printed + * @return this {@link LogStream} instance + */ + public LogStream print(int i) { + if (ps != null) { + indent(); + lineBuffer.append(i); + } + return this; + } + + /** + * Writes an int value to this stream followed by a {@linkplain #LINE_SEPARATOR line separator}. + * + * @param i the value to be printed + * @return this {@link LogStream} instance + */ + public LogStream println(int i) { + if (ps != null) { + indent(); + lineBuffer.append(i); + return flushLine(true); + } + return this; + } + + /** + * Writes a float value to this stream. + * + * @param f the value to be printed + * @return this {@link LogStream} instance + */ + public LogStream print(float f) { + if (ps != null) { + indent(); + lineBuffer.append(f); + } + return this; + } + + /** + * Writes a float value to this stream followed by a {@linkplain #LINE_SEPARATOR line separator}. + * + * @param f the value to be printed + * @return this {@link LogStream} instance + */ + public LogStream println(float f) { + if (ps != null) { + indent(); + lineBuffer.append(f); + return flushLine(true); + } + return this; + } + + /** + * Writes a long value to this stream. + * + * @param l the value to be printed + * @return this {@link LogStream} instance + */ + public LogStream print(long l) { + if (ps != null) { + indent(); + lineBuffer.append(l); + } + return this; + } + + /** + * Writes a long value to this stream followed by a {@linkplain #LINE_SEPARATOR line separator}. + * + * @param l the value to be printed + * @return this {@link LogStream} instance + */ + public LogStream println(long l) { + if (ps != null) { + indent(); + lineBuffer.append(l); + return flushLine(true); + } + return this; + } + + /** + * Writes a double value to this stream. + * + * @param d the value to be printed + * @return this {@link LogStream} instance + */ + public LogStream print(double d) { + if (ps != null) { + indent(); + lineBuffer.append(d); + } + return this; + } + + /** + * Writes a double value to this stream followed by a {@linkplain #LINE_SEPARATOR line separator}. + * + * @param d the value to be printed + * @return this {@link LogStream} instance + */ + public LogStream println(double d) { + if (ps != null) { + indent(); + lineBuffer.append(d); + return flushLine(true); + } + return this; + } + + /** + * Writes a {@code String} value to this stream. This method ensures that the {@linkplain #position() position} + * of this stream is updated correctly with respect to any {@linkplain #LINE_SEPARATOR line separators} + * present in {@code s}. + * + * @param s the value to be printed + * @return this {@link LogStream} instance + */ + public LogStream print(String s) { + if (ps != null) { + if (s == null) { + indent(); + lineBuffer.append(s); + return this; + } + + int index = 0; + int next = s.indexOf(LINE_SEPARATOR, index); + while (index < s.length()) { + indent(); + if (next > index) { + lineBuffer.append(s.substring(index, next)); + flushLine(true); + index = next + LINE_SEPARATOR.length(); + next = s.indexOf(LINE_SEPARATOR, index); + } else { + lineBuffer.append(s.substring(index)); + break; + } + } + } + return this; + } + + /** + * Writes a {@code String} value to this stream followed by a {@linkplain #LINE_SEPARATOR line separator}. + * + * @param s the value to be printed + * @return this {@link LogStream} instance + */ + public LogStream println(String s) { + if (ps != null) { + print(s); + flushLine(true); + } + return this; + } + + /** + * Writes a formatted string to this stream. + * + * @param format a format string as described in {@link String#format(String, Object...)} + * @param args the arguments to be formatted + * @return this {@link LogStream} instance + */ + public LogStream printf(String format, Object... args) { + if (ps != null) { + print(String.format(format, args)); + } + return this; + } + + /** + * Writes an instruction formatted as a {@linkplain com.oracle.max.graal.compiler.util.Util#valueString(com.oracle.max.graal.compiler.ir.Value) value} to this stream. + * + * @param value the instruction to print + * @return this {@code LogStream} instance + */ + public LogStream print(Value value) { + if (ps != null) { + indent(); + lineBuffer.append(Util.valueString(value)); + } + return this; + } + + /** + * Writes an instruction formatted as a {@linkplain com.oracle.max.graal.compiler.util.Util#valueString(com.oracle.max.graal.compiler.ir.Value) value} to this stream + * followed by a {@linkplain #LINE_SEPARATOR line separator}. + * + * @param value the instruction to print + * @return this {@code LogStream} instance + */ + public LogStream println(Value value) { + if (ps != null) { + print(value); + flushLine(true); + } + return this; + } + + /** + * Writes a {@linkplain #LINE_SEPARATOR line separator} to this stream. + * + * @return this {@code LogStream} instance + */ + public LogStream println() { + if (ps != null) { + indent(); + flushLine(true); + } + return this; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/debug/TTY.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/debug/TTY.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,239 @@ +/* + * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.debug; + +import java.io.*; +import java.util.regex.*; + +import com.oracle.max.graal.compiler.util.*; + + +/** + * A collection of static methods for printing debug and informational output to a global {@link LogStream}. + * The output can be (temporarily) suppressed per thread through use of a {@linkplain Filter filter}. + * + * @author Doug Simon + */ +public class TTY { + + /** + * Support for thread-local suppression of {@link TTY}. + * + * @author Doug Simon + */ + public static class Filter { + private LogStream previous; + private final Thread thread = Thread.currentThread(); + + /** + * Creates an object that will suppress {@link TTY} for the current thread if the given filter does not + * {@linkplain #matches(String, Object) match} the given object. To revert the suppression state to how it was + * before this call, the {@link #remove()} method must be called on the suppression object. + * + * @param filter the pattern for matching. If {@code null}, then the match is successful. If it starts with "~", + * then a regular expression {@linkplain Pattern#matches(String, CharSequence) match} is performed + * where the regular expression is specified by {@code filter} without the "~" prefix. Otherwise, a + * simple {@linkplain String#contains(CharSequence) substring} match is performed where {@code + * filter} is the substring used. + * @param object an object whose {@linkplain Object#toString() string} value is matched against {@code filter} + */ + public Filter(String filter, Object object) { + boolean suppressed = false; + if (filter != null) { + String input = object.toString(); + if (filter.startsWith("~")) { + suppressed = !Pattern.matches(filter.substring(1), input); + } else { + suppressed = !input.contains(filter); + } + if (suppressed) { + previous = out(); + out.set(LogStream.SINK); + } + } + } + + /** + * Reverts the suppression state of {@link TTY} to how it was before this object was constructed. + */ + public void remove() { + assert thread == Thread.currentThread(); + if (previous != null) { + out.set(previous); + } + } + } + + public static final String C1X_TTY_LOG_FILE_PROPERTY = "c1x.tty.file"; + + private static final LogStream log; + static { + PrintStream out = System.out; + String value = System.getProperty(C1X_TTY_LOG_FILE_PROPERTY); + if (value != null) { + try { + out = new PrintStream(new FileOutputStream(value)); + } catch (FileNotFoundException e) { + Util.warning("Could not open log file " + value + ": " + e); + } + } + log = new LogStream(out); + } + + private static final ThreadLocal out = new ThreadLocal() { + @Override + protected LogStream initialValue() { + return log; + }; + }; + + public static boolean isSuppressed() { + return out.get() == LogStream.SINK; + } + + /** + * Gets the thread-local log stream to which the static methods of this class send their output. + * This will either be a global log stream or the global {@linkplain LogStream#SINK sink} depending + * on whether any suppression {@linkplain Filter filters} are in effect for the current thread. + */ + public static LogStream out() { + return out.get(); + } + + /** + * @see LogStream#print(String) + */ + public static void print(String s) { + out().print(s); + } + + /** + * @see LogStream#print(int) + */ + public static void print(int i) { + out().print(i); + } + + /** + * @see LogStream#print(long) + */ + public static void print(long i) { + out().print(i); + } + + /** + * @see LogStream#print(char) + */ + public static void print(char c) { + out().print(c); + } + + /** + * @see LogStream#print(boolean) + */ + public static void print(boolean b) { + out().print(b); + } + + /** + * @see LogStream#print(double) + */ + public static void print(double d) { + out().print(d); + } + + /** + * @see LogStream#print(float) + */ + public static void print(float f) { + out().print(f); + } + + /** + * @see LogStream#println(String) + */ + public static void println(String s) { + out().println(s); + } + + /** + * @see LogStream#println() + */ + public static void println() { + out().println(); + } + + /** + * @see LogStream#println(int) + */ + public static void println(int i) { + out().println(i); + } + + /** + * @see LogStream#println(long) + */ + public static void println(long l) { + out().println(l); + } + + /** + * @see LogStream#println(char) + */ + public static void println(char c) { + out().println(c); + } + + /** + * @see LogStream#println(boolean) + */ + public static void println(boolean b) { + out().println(b); + } + + /** + * @see LogStream#println(double) + */ + public static void println(double d) { + out().println(d); + } + + /** + * @see LogStream#println(float) + */ + public static void println(float f) { + out().println(f); + } + + public static void print(String format, Object... args) { + out().printf(format, args); + } + + public static void println(String format, Object... args) { + out().printf(format + "%n", args); + } + + public static void fillTo(int i) { + out().fillTo(i, ' '); + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/debug/package-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/debug/package-info.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2010, 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +/** + * A collection of debugging aids for C1X development. + */ +package com.oracle.max.graal.compiler.debug; diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/LIRGenerator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/LIRGenerator.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,1645 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.gen; + +import static com.sun.cri.bytecode.Bytecodes.*; +import static com.sun.cri.bytecode.Bytecodes.MemoryBarriers.*; +import static com.sun.cri.ci.CiCallingConvention.Type.*; +import static com.sun.cri.ci.CiValue.*; + +import java.lang.reflect.*; +import java.util.*; + +import com.oracle.max.asm.*; +import com.oracle.max.graal.compiler.*; +import com.oracle.max.graal.compiler.alloc.*; +import com.oracle.max.graal.compiler.alloc.OperandPool.*; +import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.compiler.globalstub.*; +import com.oracle.max.graal.compiler.graph.*; +import com.oracle.max.graal.compiler.ir.*; +import com.oracle.max.graal.compiler.lir.*; +import com.oracle.max.graal.compiler.util.*; +import com.oracle.max.graal.compiler.value.*; +import com.oracle.max.graal.graph.*; +import com.sun.cri.ci.*; +import com.sun.cri.ri.*; +import com.sun.cri.xir.*; +import com.sun.cri.xir.CiXirAssembler.*; + +/** + * This class traverses the HIR instructions and generates LIR instructions from them. + */ +public abstract class LIRGenerator extends ValueVisitor { + + /** + * Helper class for inserting memory barriers as necessary to implement the Java Memory Model + * with respect to volatile field accesses. + * + * @see MemoryBarriers + */ + class VolatileMemoryAccess { + /** + * Inserts any necessary memory barriers before a volatile write as required by the JMM. + */ + void preVolatileWrite() { + int barriers = compilation.target.arch.requiredBarriers(JMM_PRE_VOLATILE_WRITE); + if (compilation.target.isMP && barriers != 0) { + lir.membar(barriers); + } + } + + /** + * Inserts any necessary memory barriers after a volatile write as required by the JMM. + */ + void postVolatileWrite() { + int barriers = compilation.target.arch.requiredBarriers(JMM_POST_VOLATILE_WRITE); + if (compilation.target.isMP && barriers != 0) { + lir.membar(barriers); + } + } + + /** + * Inserts any necessary memory barriers before a volatile read as required by the JMM. + */ + void preVolatileRead() { + int barriers = compilation.target.arch.requiredBarriers(JMM_PRE_VOLATILE_READ); + if (compilation.target.isMP && barriers != 0) { + lir.membar(barriers); + } + } + + /** + * Inserts any necessary memory barriers after a volatile read as required by the JMM. + */ + void postVolatileRead() { + // Ensure field's data is loaded before any subsequent loads or stores. + int barriers = compilation.target.arch.requiredBarriers(LOAD_LOAD | LOAD_STORE); + if (compilation.target.isMP && barriers != 0) { + lir.membar(barriers); + } + } + } + + /** + * Forces the result of a given instruction to be available in a given register, + * inserting move instructions if necessary. + * + * @param instruction an instruction that produces a {@linkplain Value#operand() result} + * @param register the {@linkplain CiRegister} in which the result of {@code instruction} must be available + * @return {@code register} as an operand + */ + protected CiValue force(Value instruction, CiRegister register) { + return force(instruction, register.asValue(instruction.kind)); + } + + /** + * Forces the result of a given instruction to be available in a given operand, + * inserting move instructions if necessary. + * + * @param instruction an instruction that produces a {@linkplain Value#operand() result} + * @param operand the operand in which the result of {@code instruction} must be available + * @return {@code operand} + */ + protected CiValue force(Value instruction, CiValue operand) { + CiValue result = makeOperand(instruction); + if (result != operand) { + assert result.kind != CiKind.Illegal; + if (!compilation.archKindsEqual(result.kind, operand.kind)) { + // moves between different types need an intervening spill slot + CiValue tmp = forceToSpill(result, operand.kind, false); + lir.move(tmp, operand); + } else { + lir.move(result, operand); + } + } + return operand; + } + + protected CiValue load(Value val) { + CiValue result = makeOperand(val); + if (!result.isVariableOrRegister()) { + CiVariable operand = newVariable(val.kind); + lir.move(result, operand); + return operand; + } + return result; + } + + // the range of values in a lookupswitch or tableswitch statement + private static final class SwitchRange { + final int lowKey; + int highKey; + final LIRBlock sux; + + SwitchRange(int lowKey, LIRBlock sux) { + this.lowKey = lowKey; + this.highKey = lowKey; + this.sux = sux; + } + } + + protected final C1XCompilation compilation; + protected final IR ir; + protected final XirSupport xirSupport; + protected final RiXirGenerator xir; + protected final boolean isTwoOperand; + + private LIRBlock currentBlock; + + public final OperandPool operands; + + private Value currentInstruction; + private Value lastInstructionPrinted; // Debugging only + + private List constants; + private List variablesForConstants; + protected LIRList lir; + final VolatileMemoryAccess vma; + private ArrayList deoptimizationStubs; + private FrameState lastState; + + public LIRGenerator(C1XCompilation compilation) { + this.compilation = compilation; + this.ir = compilation.hir(); + this.xir = compilation.compiler.xir; + this.xirSupport = new XirSupport(); + this.isTwoOperand = compilation.target.arch.twoOperandMode(); + this.vma = new VolatileMemoryAccess(); + + constants = new ArrayList(); + variablesForConstants = new ArrayList(); + + this.operands = new OperandPool(compilation.target); + } + + public ArrayList deoptimizationStubs() { + return deoptimizationStubs; + } + + private void addDeoptimizationStub(DeoptimizationStub stub) { + if (deoptimizationStubs == null) { + deoptimizationStubs = new ArrayList(); + } + deoptimizationStubs.add(stub); + } + + public static class DeoptimizationStub { + public final Label label = new Label(); + public final LIRDebugInfo info; + + public DeoptimizationStub(FrameState state) { + info = new LIRDebugInfo(state); + } + } + + public void doBlock(LIRBlock block) { + blockDoProlog(block); + this.currentBlock = block; + + if (C1XOptions.TraceLIRGeneratorLevel >= 1) { + TTY.println("BEGIN Generating LIR for block B" + block.blockID()); + } + + if (block.blockPredecessors().size() > 1) { + lastState = null; + } + + for (Node instr : block.getInstructions()) { + FrameState stateAfter = null; + if (instr instanceof Instruction) { + stateAfter = ((Instruction) instr).stateAfter(); + } + FrameState stateBefore = null; + if (instr instanceof StateSplit && ((StateSplit) instr).stateBefore() != null) { + stateBefore = ((StateSplit) instr).stateBefore(); + } + if (stateBefore != null) { + lastState = stateBefore; + if (C1XOptions.TraceLIRGeneratorLevel >= 2) { + TTY.println("STATE CHANGE (stateBefore)"); + if (C1XOptions.TraceLIRGeneratorLevel >= 3) { + TTY.println(stateBefore.toString()); + } + } + } + if (!(instr instanceof Merge) && instr != instr.graph().start()) { + walkState(instr, stateAfter); + doRoot((Value) instr); + } + if (stateAfter != null) { + lastState = stateAfter; + if (C1XOptions.TraceLIRGeneratorLevel >= 2) { + TTY.println("STATE CHANGE"); + if (C1XOptions.TraceLIRGeneratorLevel >= 3) { + TTY.println(stateAfter.toString()); + } + } + } + } + if (block.blockSuccessors().size() >= 1 && (block.getInstructions().size() == 0 || !jumpsToNextBlock(block.getInstructions().get(block.getInstructions().size() - 1)))) { + moveToPhi(); + block.lir().jump(block.blockSuccessors().get(0)); + } + + if (C1XOptions.TraceLIRGeneratorLevel >= 1) { + TTY.println("END Generating LIR for block B" + block.blockID()); + } + + block.setLastState(lastState); + this.currentBlock = null; + blockDoEpilog(); + } + + private static boolean jumpsToNextBlock(Node node) { + return node instanceof BlockEnd; + } + + @Override + public void visitArrayLength(ArrayLength x) { + emitArrayLength(x); + } + + public CiValue emitArrayLength(ArrayLength x) { + XirArgument array = toXirArgument(x.array()); + XirSnippet snippet = xir.genArrayLength(site(x), array); + emitXir(snippet, x, stateFor(x), null, true); + return x.operand(); + } + + private FrameState setOperandsForLocals() { + CiCallingConvention args = compilation.frameMap().incomingArguments(); + int bci = 0; + if (Modifier.isSynchronized(compilation.method.accessFlags())) { + bci = Instruction.SYNCHRONIZATION_ENTRY_BCI; + } + FrameState fs = new FrameState(compilation.method, bci, compilation.method.maxLocals(), 0, 0, compilation.graph); + for (Node node : compilation.graph.start().usages()) { + if (node instanceof Local) { + Local local = (Local) node; + int i = local.index(); + fs.storeLocal(i, local); + + CiValue src = args.locations[i]; + assert src.isLegal() : "check"; + + CiVariable dest = newVariable(src.kind.stackKind()); + lir.move(src, dest, src.kind); + + assert src.kind.stackKind() == local.kind.stackKind() : "local type check failed"; + setResult(local, dest); + } + } + return fs; + } + + @Override + public void visitCheckCast(CheckCast x) { + XirArgument obj = toXirArgument(x.object()); + XirSnippet snippet = xir.genCheckCast(site(x), obj, toXirArgument(x.targetClassInstruction()), x.targetClass()); + emitXir(snippet, x, stateFor(x), null, true); + } + + @Override + public void visitInstanceOf(InstanceOf x) { + XirArgument obj = toXirArgument(x.object()); + XirSnippet snippet = xir.genInstanceOf(site(x), obj, toXirArgument(x.targetClassInstruction()), x.targetClass()); + emitXir(snippet, x, stateFor(x), null, true); + } + + @Override + public void visitMonitorEnter(MonitorEnter x) { + XirArgument obj = toXirArgument(x.object()); + XirArgument lockAddress = toXirArgument(x.lockAddress()); + XirSnippet snippet = xir.genMonitorEnter(site(x), obj, lockAddress); + emitXir(snippet, x, stateFor(x), stateFor(x, x.stateAfter()), null, true, null); + } + + @Override + public void visitMonitorExit(MonitorExit x) { + XirArgument obj = toXirArgument(x.object()); + XirArgument lockAddress = toXirArgument(x.lockAddress()); + XirSnippet snippet = xir.genMonitorExit(site(x), obj, lockAddress); + emitXir(snippet, x, stateFor(x), null, true); + } + + @Override + public void visitStoreIndexed(StoreIndexed x) { + XirArgument array = toXirArgument(x.array()); + XirArgument length = x.length() == null ? null : toXirArgument(x.length()); + XirArgument index = toXirArgument(x.index()); + XirArgument value = toXirArgument(x.value()); + XirSnippet snippet = xir.genArrayStore(site(x), array, index, length, value, x.elementKind(), null); + emitXir(snippet, x, stateFor(x), null, true); + } + + @Override + public void visitNewInstance(NewInstance x) { + XirSnippet snippet = xir.genNewInstance(site(x), x.instanceClass()); + emitXir(snippet, x, stateFor(x), null, true); + } + + @Override + public void visitNewTypeArray(NewTypeArray x) { + XirArgument length = toXirArgument(x.length()); + XirSnippet snippet = xir.genNewArray(site(x), length, x.elementKind(), null, null); + emitXir(snippet, x, stateFor(x), null, true); + } + + @Override + public void visitNewObjectArray(NewObjectArray x) { + XirArgument length = toXirArgument(x.length()); + XirSnippet snippet = xir.genNewArray(site(x), length, CiKind.Object, x.elementClass(), x.exactType()); + emitXir(snippet, x, stateFor(x), null, true); + } + + @Override + public void visitNewMultiArray(NewMultiArray x) { + XirArgument[] dims = new XirArgument[x.dimensionCount()]; + + for (int i = 0; i < dims.length; i++) { + dims[i] = toXirArgument(x.dimension(i)); + } + + XirSnippet snippet = xir.genNewMultiArray(site(x), dims, x.elementType); + emitXir(snippet, x, stateFor(x), null, true); + } + + @Override + public void visitConstant(Constant x) { + if (!canInlineAsConstant(x)) { + CiValue res = x.operand(); + if (!(res.isLegal())) { + res = x.asConstant(); + } + if (res.isConstant()) { + CiVariable reg = createResultVariable(x); + lir.move(res, reg); + } else { + setResult(x, (CiVariable) res); + } + } + } + + @Override + public void visitExceptionObject(ExceptionObject x) { + XirSnippet snippet = xir.genExceptionObject(site(x)); + emitXir(snippet, x, stateFor(x), null, true); + } + + @Override + public void visitAnchor(Anchor x) { + setNoResult(x); + + // emit phi-instruction moves after safepoint since this simplifies + // describing the state at the safepoint. + + moveToPhi(); + lir.jump(getLIRBlock(x.defaultSuccessor())); + } + + @Override + public void visitIfOp(Conditional i) { + Value x = i.x(); + Value y = i.y(); + CiKind xtype = x.kind; + CiKind ttype = i.trueValue().kind; + assert xtype.isInt() || xtype.isObject() : "cannot handle others"; + assert ttype.isInt() || ttype.isObject() || ttype.isLong() || ttype.isWord() : "cannot handle others"; + assert ttype.equals(i.falseValue().kind) : "cannot handle others"; + + CiValue left = load(x); + CiValue right = null; + if (!canInlineAsConstant(y)) { + right = load(y); + } else { + right = makeOperand(y); + } + + CiValue tVal = makeOperand(i.trueValue()); + CiValue fVal = makeOperand(i.falseValue()); + CiValue reg = createResultVariable(i); + + lir.cmp(i.condition(), left, right); + lir.cmove(i.condition(), tVal, fVal, reg); + } + + protected FrameState stateBeforeInvokeReturn(Invoke invoke) { + return invoke.stateAfter().duplicateModified(getBeforeInvokeBci(invoke), invoke.kind); + } + + protected FrameState stateBeforeInvokeWithArguments(Invoke invoke) { + Value[] args = new Value[invoke.argumentCount()]; + for (int i = 0; i < invoke.argumentCount(); i++) { + args[i] = invoke.argument(i); + } + return invoke.stateAfter().duplicateModified(getBeforeInvokeBci(invoke), invoke.kind, args); + } + + private int getBeforeInvokeBci(Invoke invoke) { + /*int length = 3; + if (invoke.opcode() == Bytecodes.INVOKEINTERFACE) { + length += 2; + } + return invoke.stateAfter().bci - length;*/ + return invoke.bci; + } + + @Override + public void visitInvoke(Invoke x) { + RiMethod target = x.target(); + LIRDebugInfo info = stateFor(x, stateBeforeInvokeWithArguments(x)); + LIRDebugInfo info2 = stateFor(x, stateBeforeInvokeReturn(x)); + if (x.exceptionEdge() != null) { + info2.setExceptionEdge(getLIRBlock(x.exceptionEdge())); + } + + XirSnippet snippet = null; + + int opcode = x.opcode(); + XirArgument receiver; + switch (opcode) { + case INVOKESTATIC: + snippet = xir.genInvokeStatic(site(x), target); + break; + case INVOKESPECIAL: + receiver = toXirArgument(x.receiver()); + snippet = xir.genInvokeSpecial(site(x), receiver, target); + break; + case INVOKEVIRTUAL: + receiver = toXirArgument(x.receiver()); + snippet = xir.genInvokeVirtual(site(x), receiver, target); + break; + case INVOKEINTERFACE: + receiver = toXirArgument(x.receiver()); + snippet = xir.genInvokeInterface(site(x), receiver, target); + break; + } + + CiValue destinationAddress = null; + // emitting the template earlier can ease pressure on register allocation, but the argument loading can destroy an + // implicit calling convention between the XirSnippet and the call. + if (!C1XOptions.InvokeSnippetAfterArguments) { + destinationAddress = emitXir(snippet, x, info.copy(), x.target(), false); + } + + CiValue resultOperand = resultOperandFor(x.kind); + CiCallingConvention cc = compilation.frameMap().getCallingConvention(x.signature(), JavaCall); + List pointerSlots = new ArrayList(2); + List argList = visitInvokeArguments(cc, x, pointerSlots); + + if (C1XOptions.InvokeSnippetAfterArguments) { + destinationAddress = emitXir(snippet, x, info.copy(), null, x.target(), false, pointerSlots); + } + + // emit direct or indirect call to the destination address + if (destinationAddress instanceof CiConstant) { + // Direct call + assert ((CiConstant) destinationAddress).isDefaultValue() : "destination address should be zero"; + lir.callDirect(target, resultOperand, argList, info2, snippet.marks, pointerSlots); + } else { + // Indirect call + argList.add(destinationAddress); + lir.callIndirect(target, resultOperand, argList, info2, snippet.marks, pointerSlots); + } + + if (resultOperand.isLegal()) { + CiValue result = createResultVariable(x); + lir.move(resultOperand, result); + } + } + + @Override + public void visitMonitorAddress(MonitorAddress x) { + CiValue result = createResultVariable(x); + lir.monitorAddress(x.monitor(), result); + } + + /** + * For note on volatile fields, see {@link #visitStoreField(StoreField)}. + */ + @Override + public void visitLoadField(LoadField x) { + RiField field = x.field(); + LIRDebugInfo info = stateFor(x); + XirArgument receiver = toXirArgument(x.object()); + XirSnippet snippet = x.isStatic() ? xir.genGetStatic(site(x), receiver, field) : xir.genGetField(site(x), receiver, field); + emitXir(snippet, x, info, null, true); + + if (x.isVolatile()) { + vma.postVolatileRead(); + } + } + + @Override + public void visitLoadIndexed(LoadIndexed x) { + XirArgument array = toXirArgument(x.array()); + XirArgument index = toXirArgument(x.index()); + XirArgument length = toXirArgument(x.length()); + XirSnippet snippet = xir.genArrayLoad(site(x), array, index, length, x.elementKind(), null); + emitXir(snippet, x, stateFor(x), null, true); + } + + protected GlobalStub stubFor(CiRuntimeCall runtimeCall) { + GlobalStub stub = compilation.compiler.lookupGlobalStub(runtimeCall); + compilation.frameMap().usesGlobalStub(stub); + return stub; + } + + protected GlobalStub stubFor(GlobalStub.Id globalStub) { + GlobalStub stub = compilation.compiler.lookupGlobalStub(globalStub); + compilation.frameMap().usesGlobalStub(stub); + return stub; + } + + protected GlobalStub stubFor(XirTemplate template) { + GlobalStub stub = compilation.compiler.lookupGlobalStub(template); + compilation.frameMap().usesGlobalStub(stub); + return stub; + } + + @Override + public void visitLocal(Local x) { + if (x.operand().isIllegal()) { + createResultVariable(x); + } + } + + @Override + public void visitLookupSwitch(LookupSwitch x) { + CiValue tag = load(x.value()); + setNoResult(x); + + if (x.numberOfCases() == 0 || x.numberOfCases() < C1XOptions.SequentialSwitchLimit) { + int len = x.numberOfCases(); + for (int i = 0; i < len; i++) { + lir.cmp(Condition.EQ, tag, x.keyAt(i)); + lir.branch(Condition.EQ, CiKind.Int, getLIRBlock(x.blockSuccessor(i))); + } + lir.jump(getLIRBlock(x.defaultSuccessor())); + } else { + visitSwitchRanges(createLookupRanges(x), tag, getLIRBlock(x.defaultSuccessor())); + } + } + + protected LIRBlock getLIRBlock(Instruction b) { + LIRBlock result = ir.valueToBlock.get(b); + if (result == null) { + TTY.println("instruction without lir block: " + b); + } + return result; + } + + @Override + public void visitNullCheck(NullCheck x) { + CiValue value = load(x.object()); + LIRDebugInfo info = stateFor(x); + lir.nullCheck(value, info); + } + + @Override + public void visitPhi(Phi i) { + Util.shouldNotReachHere(); + } + + @Override + public void visitReturn(Return x) { + if (x.kind.isVoid()) { + XirSnippet epilogue = xir.genEpilogue(site(x), compilation.method); + if (epilogue != null) { + emitXir(epilogue, x, null, compilation.method, false); + lir.returnOp(IllegalValue); + } + } else { + CiValue operand = resultOperandFor(x.kind); + CiValue result = force(x.result(), operand); + XirSnippet epilogue = xir.genEpilogue(site(x), compilation.method); + if (epilogue != null) { + emitXir(epilogue, x, null, compilation.method, false); + lir.returnOp(result); + } + } + setNoResult(x); + } + + protected XirArgument toXirArgument(CiValue v) { + if (v == null) { + return null; + } + + return XirArgument.forInternalObject(v); + } + + protected XirArgument toXirArgument(Value i) { + if (i == null) { + return null; + } + + return XirArgument.forInternalObject(new LIRItem(i, this)); + } + + private CiValue allocateOperand(XirSnippet snippet, XirOperand op) { + if (op instanceof XirParameter) { + XirParameter param = (XirParameter) op; + return allocateOperand(snippet.arguments[param.parameterIndex], op, param.canBeConstant); + } else if (op instanceof XirRegister) { + XirRegister reg = (XirRegister) op; + return reg.register; + } else if (op instanceof XirTemp) { + return newVariable(op.kind); + } else { + Util.shouldNotReachHere(); + return null; + } + } + + private CiValue allocateOperand(XirArgument arg, XirOperand var, boolean canBeConstant) { + if (arg.constant != null) { + return arg.constant; + } else { + assert arg.object != null; + if (arg.object instanceof CiValue) { + return (CiValue) arg.object; + } + assert arg.object instanceof LIRItem; + LIRItem item = (LIRItem) arg.object; + if (canBeConstant) { + return item.instruction.operand(); + } else { + CiKind kind = var.kind; + if (kind == CiKind.Byte || kind == CiKind.Boolean) { + item.loadByteItem(); + } else { + item.loadItem(); + } + return item.result(); + } + } + } + + protected CiValue emitXir(XirSnippet snippet, Value x, LIRDebugInfo info, RiMethod method, boolean setInstructionResult) { + return emitXir(snippet, x, info, null, method, setInstructionResult, null); + } + + protected CiValue emitXir(XirSnippet snippet, Value instruction, LIRDebugInfo info, LIRDebugInfo infoAfter, RiMethod method, boolean setInstructionResult, List pointerSlots) { + if (C1XOptions.PrintXirTemplates) { + TTY.println("Emit XIR template " + snippet.template.name); + } + + final CiValue[] operands = new CiValue[snippet.template.variableCount]; + + compilation.frameMap().reserveOutgoing(snippet.template.outgoingStackSize); + + XirOperand resultOperand = snippet.template.resultOperand; + + if (snippet.template.allocateResultOperand) { + CiValue outputOperand = IllegalValue; + // This snippet has a result that must be separately allocated + // Otherwise it is assumed that the result is part of the inputs + if (resultOperand.kind != CiKind.Void && resultOperand.kind != CiKind.Illegal) { + if (setInstructionResult) { + outputOperand = newVariable(instruction.kind); + } else { + outputOperand = newVariable(resultOperand.kind); + } + assert operands[resultOperand.index] == null; + } + operands[resultOperand.index] = outputOperand; + if (C1XOptions.PrintXirTemplates) { + TTY.println("Output operand: " + outputOperand); + } + } + + for (XirTemp t : snippet.template.temps) { + if (t instanceof XirRegister) { + XirRegister reg = (XirRegister) t; + if (!t.reserve) { + operands[t.index] = reg.register; + } + } + } + + for (XirTemplate calleeTemplate : snippet.template.calleeTemplates) { + // TODO Save these for use in X86LIRAssembler + stubFor(calleeTemplate); + } + + for (XirConstant c : snippet.template.constants) { + assert operands[c.index] == null; + operands[c.index] = c.value; + } + + XirOperand[] inputOperands = snippet.template.inputOperands; + XirOperand[] inputTempOperands = snippet.template.inputTempOperands; + XirOperand[] tempOperands = snippet.template.tempOperands; + + CiValue[] operandArray = new CiValue[inputOperands.length + inputTempOperands.length + tempOperands.length]; + int[] operandIndicesArray = new int[inputOperands.length + inputTempOperands.length + tempOperands.length]; + for (int i = 0; i < inputOperands.length; i++) { + XirOperand x = inputOperands[i]; + CiValue op = allocateOperand(snippet, x); + operands[x.index] = op; + operandArray[i] = op; + operandIndicesArray[i] = x.index; + if (C1XOptions.PrintXirTemplates) { + TTY.println("Input operand: " + x); + } + } + + for (int i = 0; i < inputTempOperands.length; i++) { + XirOperand x = inputTempOperands[i]; + CiValue op = allocateOperand(snippet, x); + CiValue newOp = newVariable(op.kind); + lir.move(op, newOp); + operands[x.index] = newOp; + operandArray[i + inputOperands.length] = newOp; + operandIndicesArray[i + inputOperands.length] = x.index; + if (C1XOptions.PrintXirTemplates) { + TTY.println("InputTemp operand: " + x); + } + } + + for (int i = 0; i < tempOperands.length; i++) { + XirOperand x = tempOperands[i]; + CiValue op = allocateOperand(snippet, x); + operands[x.index] = op; + operandArray[i + inputOperands.length + inputTempOperands.length] = op; + operandIndicesArray[i + inputOperands.length + inputTempOperands.length] = x.index; + if (C1XOptions.PrintXirTemplates) { + TTY.println("Temp operand: " + x); + } + } + + for (CiValue operand : operands) { + assert operand != null; + } + + CiValue allocatedResultOperand = operands[resultOperand.index]; + if (!allocatedResultOperand.isVariableOrRegister()) { + allocatedResultOperand = IllegalValue; + } + + if (setInstructionResult && allocatedResultOperand.isLegal()) { + if (instruction.operand().isIllegal()) { + setResult(instruction, (CiVariable) allocatedResultOperand); + } else { + assert instruction.operand() == allocatedResultOperand; + } + } + + + XirInstruction[] slowPath = snippet.template.slowPath; + if (!operands[resultOperand.index].isConstant() || snippet.template.fastPath.length != 0 || (slowPath != null && slowPath.length > 0)) { + // XIR instruction is only needed when the operand is not a constant! + lir.xir(snippet, operands, allocatedResultOperand, inputTempOperands.length, tempOperands.length, + operandArray, operandIndicesArray, + (operands[resultOperand.index] == IllegalValue) ? -1 : resultOperand.index, + info, infoAfter, method, pointerSlots); + } + + return operands[resultOperand.index]; + } + + @Override + public void visitStoreField(StoreField x) { + RiField field = x.field(); + LIRDebugInfo info = stateFor(x); + + if (x.isVolatile()) { + vma.preVolatileWrite(); + } + + XirArgument receiver = toXirArgument(x.object()); + XirArgument value = toXirArgument(x.value()); + XirSnippet snippet = x.isStatic() ? xir.genPutStatic(site(x), receiver, field, value) : xir.genPutField(site(x), receiver, field, value); + emitXir(snippet, x, info, null, true); + + if (x.isVolatile()) { + vma.postVolatileWrite(); + } + } + + @Override + public void visitTableSwitch(TableSwitch x) { + + LIRItem value = new LIRItem(x.value(), this); + // Making a copy of the switch value is necessary when generating a jump table + value.setDestroysRegister(); + value.loadItem(); + + CiValue tag = value.result(); + setNoResult(x); + + // TODO: tune the defaults for the controls used to determine what kind of translation to use + if (x.numberOfCases() == 0 || x.numberOfCases() <= C1XOptions.SequentialSwitchLimit) { + int loKey = x.lowKey(); + int len = x.numberOfCases(); + for (int i = 0; i < len; i++) { + lir.cmp(Condition.EQ, tag, i + loKey); + lir.branch(Condition.EQ, CiKind.Int, getLIRBlock(x.blockSuccessor(i))); + } + lir.jump(getLIRBlock(x.defaultSuccessor())); + } else { + SwitchRange[] switchRanges = createLookupRanges(x); + int rangeDensity = x.numberOfCases() / switchRanges.length; + if (rangeDensity >= C1XOptions.RangeTestsSwitchDensity) { + visitSwitchRanges(switchRanges, tag, getLIRBlock(x.defaultSuccessor())); + } else { + List nonDefaultSuccessors = x.blockSuccessors().subList(0, x.numberOfCases()); + LIRBlock[] targets = new LIRBlock[nonDefaultSuccessors.size()]; + for (int i = 0; i < nonDefaultSuccessors.size(); ++i) { + targets[i] = getLIRBlock(nonDefaultSuccessors.get(i)); + } + lir.tableswitch(tag, x.lowKey(), getLIRBlock(x.defaultSuccessor()), targets); + } + } + } + + @Override + public void visitDeoptimize(Deoptimize deoptimize) { + DeoptimizationStub stub = new DeoptimizationStub(lastState); + addDeoptimizationStub(stub); + lir.branch(Condition.TRUE, stub.label, stub.info); + } + + private void blockDoEpilog() { + if (C1XOptions.PrintIRWithLIR) { + TTY.println(); + } + + // clear out variables for local constants + constants.clear(); + variablesForConstants.clear(); + } + + private void blockDoProlog(LIRBlock block) { + if (C1XOptions.PrintIRWithLIR) { + TTY.print(block.toString()); + } + // set up the list of LIR instructions + assert block.lir() == null : "LIR list already computed for this block"; + lir = new LIRList(this); + block.setLir(lir); + + lir.branchDestination(block.label()); + if (block == ir.startBlock) { + XirSnippet prologue = xir.genPrologue(null, compilation.method); + if (prologue != null) { + emitXir(prologue, null, null, null, false); + } + FrameState fs = setOperandsForLocals(); + lastState = fs; + } else if (block.blockPredecessors().size() == 1) { + FrameState fs = block.blockPredecessors().get(0).lastState(); + assert fs != null; + lastState = fs; + } + } + + /** + * Copies a given value into an operand that is forced to be a stack location. + * + * @param value a value to be forced onto the stack + * @param kind the kind of new operand + * @param mustStayOnStack specifies if the new operand must never be allocated to a register + * @return the operand that is guaranteed to be a stack location when it is + * initially defined a by move from {@code value} + */ + CiValue forceToSpill(CiValue value, CiKind kind, boolean mustStayOnStack) { + assert value.isLegal() : "value should not be illegal"; + assert kind.jvmSlots == value.kind.jvmSlots : "size mismatch"; + if (!value.isVariableOrRegister()) { + // force into a variable that must start in memory + CiValue operand = operands.newVariable(value.kind, mustStayOnStack ? VariableFlag.MustStayInMemory : VariableFlag.MustStartInMemory); + lir.move(value, operand); + return operand; + } + + // create a spill location + CiValue operand = operands.newVariable(kind, mustStayOnStack ? VariableFlag.MustStayInMemory : VariableFlag.MustStartInMemory); + // move from register to spill + lir.move(value, operand); + return operand; + } + + private CiVariable loadConstant(Constant x) { + return loadConstant(x.asConstant(), x.kind); + } + + protected CiVariable loadConstant(CiConstant c, CiKind kind) { + // XXX: linear search might be kind of slow for big basic blocks + int index = constants.indexOf(c); + if (index != -1) { + C1XMetrics.LoadConstantIterations += index; + return variablesForConstants.get(index); + } + C1XMetrics.LoadConstantIterations += constants.size(); + + CiVariable result = newVariable(kind); + lir.move(c, result); + constants.add(c); + variablesForConstants.add(result); + return result; + } + + /** + * Allocates a variable operand to hold the result of a given instruction. + * This can only be performed once for any given instruction. + * + * @param x an instruction that produces a result + * @return the variable assigned to hold the result produced by {@code x} + */ + protected CiVariable createResultVariable(Value x) { + CiVariable operand = newVariable(x.kind); + setResult(x, operand); + return operand; + } + + @Override + public void visitRegisterFinalizer(RegisterFinalizer x) { + CiValue receiver = load(x.object()); + LIRDebugInfo info = stateFor(x, x.stateBefore()); + callRuntime(CiRuntimeCall.RegisterFinalizer, info, receiver); + setNoResult(x); + } + + private void visitSwitchRanges(SwitchRange[] x, CiValue value, LIRBlock defaultSux) { + for (int i = 0; i < x.length; i++) { + SwitchRange oneRange = x[i]; + int lowKey = oneRange.lowKey; + int highKey = oneRange.highKey; + LIRBlock dest = oneRange.sux; + if (lowKey == highKey) { + lir.cmp(Condition.EQ, value, lowKey); + lir.branch(Condition.EQ, CiKind.Int, dest); + } else if (highKey - lowKey == 1) { + lir.cmp(Condition.EQ, value, lowKey); + lir.branch(Condition.EQ, CiKind.Int, dest); + lir.cmp(Condition.EQ, value, highKey); + lir.branch(Condition.EQ, CiKind.Int, dest); + } else { + Label l = new Label(); + lir.cmp(Condition.LT, value, lowKey); + lir.branch(Condition.LT, l); + lir.cmp(Condition.LE, value, highKey); + lir.branch(Condition.LE, CiKind.Int, dest); + lir.branchDestination(l); + } + } + lir.jump(defaultSux); + } + + protected void arithmeticOpFpu(int code, CiValue result, CiValue left, CiValue right, CiValue tmp) { + CiValue leftOp = left; + + if (isTwoOperand && leftOp != result) { + assert right != result : "malformed"; + lir.move(leftOp, result); + leftOp = result; + } + + switch (code) { + case DADD: + case FADD: + lir.add(leftOp, right, result); + break; + case FMUL: + case DMUL: + lir.mul(leftOp, right, result); + break; + case DSUB: + case FSUB: + lir.sub(leftOp, right, result); + break; + case FDIV: + case DDIV: + lir.div(leftOp, right, result, null); + break; + default: + Util.shouldNotReachHere(); + } + } + + protected void arithmeticOpInt(int code, CiValue result, CiValue left, CiValue right, CiValue tmp) { + CiValue leftOp = left; + + if (isTwoOperand && leftOp != result) { + assert right != result : "malformed"; + lir.move(leftOp, result); + leftOp = result; + } + + switch (code) { + case IADD: + lir.add(leftOp, right, result); + break; + case IMUL: + boolean didStrengthReduce = false; + if (right.isConstant()) { + CiConstant rightConstant = (CiConstant) right; + int c = rightConstant.asInt(); + if (CiUtil.isPowerOf2(c)) { + // do not need tmp here + lir.shiftLeft(leftOp, CiUtil.log2(c), result); + didStrengthReduce = true; + } else { + didStrengthReduce = strengthReduceMultiply(leftOp, c, result, tmp); + } + } + // we couldn't strength reduce so just emit the multiply + if (!didStrengthReduce) { + lir.mul(leftOp, right, result); + } + break; + case ISUB: + lir.sub(leftOp, right, result); + break; + default: + // idiv and irem are handled elsewhere + Util.shouldNotReachHere(); + } + } + + protected void arithmeticOpLong(int code, CiValue result, CiValue left, CiValue right, LIRDebugInfo info) { + CiValue leftOp = left; + + if (isTwoOperand && leftOp != result) { + assert right != result : "malformed"; + lir.move(leftOp, result); + leftOp = result; + } + + switch (code) { + case LADD: + lir.add(leftOp, right, result); + break; + case LMUL: + lir.mul(leftOp, right, result); + break; + case LSUB: + lir.sub(leftOp, right, result); + break; + default: + // ldiv and lrem are handled elsewhere + Util.shouldNotReachHere(); + } + } + + protected final CiValue callRuntime(CiRuntimeCall runtimeCall, LIRDebugInfo info, CiValue... args) { + // get a result register + CiKind result = runtimeCall.resultKind; + CiKind[] arguments = runtimeCall.arguments; + + CiValue physReg = result.isVoid() ? IllegalValue : resultOperandFor(result); + + List argumentList; + if (arguments.length > 0) { + // move the arguments into the correct location + CiCallingConvention cc = compilation.frameMap().getCallingConvention(arguments, RuntimeCall); + assert cc.locations.length == args.length : "argument count mismatch"; + for (int i = 0; i < args.length; i++) { + CiValue arg = args[i]; + CiValue loc = cc.locations[i]; + if (loc.isRegister()) { + lir.move(arg, loc); + } else { + assert loc.isStackSlot(); + CiStackSlot slot = (CiStackSlot) loc; + if (slot.kind == CiKind.Long || slot.kind == CiKind.Double) { + lir.unalignedMove(arg, slot); + } else { + lir.move(arg, slot); + } + } + } + argumentList = Arrays.asList(cc.locations); + } else { + // no arguments + assert args == null || args.length == 0; + argumentList = Util.uncheckedCast(Collections.emptyList()); + } + + lir.callRuntime(runtimeCall, physReg, argumentList, info); + + return physReg; + } + + protected final CiVariable callRuntimeWithResult(CiRuntimeCall runtimeCall, LIRDebugInfo info, CiValue... args) { + CiVariable result = newVariable(runtimeCall.resultKind); + CiValue location = callRuntime(runtimeCall, info, args); + lir.move(location, result); + return result; + } + + SwitchRange[] createLookupRanges(LookupSwitch x) { + // we expect the keys to be sorted by increasing value + List res = new ArrayList(x.numberOfCases()); + int len = x.numberOfCases(); + if (len > 0) { + LIRBlock defaultSux = getLIRBlock(x.defaultSuccessor()); + int key = x.keyAt(0); + LIRBlock sux = getLIRBlock(x.blockSuccessor(0)); + SwitchRange range = new SwitchRange(key, sux); + for (int i = 1; i < len; i++) { + int newKey = x.keyAt(i); + LIRBlock newSux = getLIRBlock(x.blockSuccessor(i)); + if (key + 1 == newKey && sux == newSux) { + // still in same range + range.highKey = newKey; + } else { + // skip tests which explicitly dispatch to the default + if (range.sux != defaultSux) { + res.add(range); + } + range = new SwitchRange(newKey, newSux); + } + key = newKey; + sux = newSux; + } + if (res.size() == 0 || res.get(res.size() - 1) != range) { + res.add(range); + } + } + return res.toArray(new SwitchRange[res.size()]); + } + + SwitchRange[] createLookupRanges(TableSwitch x) { + // XXX: try to merge this with the code for LookupSwitch + List res = new ArrayList(x.numberOfCases()); + int len = x.numberOfCases(); + if (len > 0) { + LIRBlock sux = getLIRBlock(x.blockSuccessor(0)); + int key = x.lowKey(); + LIRBlock defaultSux = getLIRBlock(x.defaultSuccessor()); + SwitchRange range = new SwitchRange(key, sux); + for (int i = 0; i < len; i++, key++) { + LIRBlock newSux = getLIRBlock(x.blockSuccessor(i)); + if (sux == newSux) { + // still in same range + range.highKey = key; + } else { + // skip tests which explicitly dispatch to the default + if (sux != defaultSux) { + res.add(range); + } + range = new SwitchRange(key, newSux); + } + sux = newSux; + } + if (res.size() == 0 || res.get(res.size() - 1) != range) { + res.add(range); + } + } + return res.toArray(new SwitchRange[res.size()]); + } + + void doRoot(Value instr) { + if (C1XOptions.TraceLIRGeneratorLevel >= 2) { + TTY.println("Emitting LIR for instruction " + instr); + } + currentInstruction = instr; + + if (C1XOptions.TraceLIRVisit) { + TTY.println("Visiting " + instr); + } + instr.accept(this); + if (C1XOptions.TraceLIRVisit) { + TTY.println("Operand for " + instr + " = " + instr.operand()); + } + } + + protected void logicOp(int code, CiValue resultOp, CiValue leftOp, CiValue rightOp) { + if (isTwoOperand && leftOp != resultOp) { + assert rightOp != resultOp : "malformed"; + lir.move(leftOp, resultOp); + leftOp = resultOp; + } + + switch (code) { + case IAND: + case LAND: + lir.logicalAnd(leftOp, rightOp, resultOp); + break; + + case IOR: + case LOR: + lir.logicalOr(leftOp, rightOp, resultOp); + break; + + case IXOR: + case LXOR: + lir.logicalXor(leftOp, rightOp, resultOp); + break; + + default: + Util.shouldNotReachHere(); + } + } + + void moveToPhi(PhiResolver resolver, Value curVal, Value suxVal, List phis, int predIndex) { + // move current value to referenced phi function + if (suxVal instanceof Phi) { + Phi phi = (Phi) suxVal; + + // curVal can be null without phi being null in conjunction with inlining + if (!phi.isDead() && curVal != null && curVal != phi) { + + assert phis.contains(phi); + if (phi.valueAt(predIndex) != curVal) { + phi.print(TTY.out()); + } + assert phi.valueAt(predIndex) == curVal : "curVal=" + curVal + "valueAt(" + predIndex + ")=" + phi.valueAt(predIndex); + + assert !phi.isDead() : "illegal phi cannot be marked as live"; + if (curVal instanceof Phi) { + operandForPhi((Phi) curVal); + } + CiValue operand = curVal.operand(); + if (operand.isIllegal()) { + assert curVal instanceof Constant || curVal instanceof Local : "these can be produced lazily"; + operand = operandForInstruction(curVal); + } + resolver.move(operand, operandForPhi(phi)); + } + } + } + + private List getPhis(LIRBlock block) { + if (block.getInstructions().size() > 0) { + Node i = block.firstInstruction(); + if (i instanceof Merge) { + List result = new ArrayList(); + for (Node n : i.usages()) { + if (n instanceof Phi) { + result.add((Phi) n); + } + } + return result; + } + } + return null; + } + + protected void moveToPhi() { + // Moves all stack values into their phi position + LIRBlock bb = currentBlock; + if (bb.numberOfSux() == 1) { + LIRBlock sux = bb.suxAt(0); + assert sux.numberOfPreds() > 0 : "invalid CFG"; + + // a block with only one predecessor never has phi functions + if (sux.numberOfPreds() > 1) { + + + List phis = getPhis(sux); + + if (phis != null) { + + int predIndex = 0; + for (; predIndex < sux.numberOfPreds(); ++predIndex) { + if (sux.predAt(predIndex) == bb) { + break; + } + } + assert predIndex < sux.numberOfPreds(); + + PhiResolver resolver = new PhiResolver(this); + for (Phi phi : phis) { + if (!phi.isDead()) { + Value curVal = phi.valueAt(predIndex); + if (curVal != null && curVal != phi) { + if (curVal instanceof Phi) { + operandForPhi((Phi) curVal); + } + CiValue operand = curVal.operand(); + if (operand.isIllegal()) { + assert curVal instanceof Constant || curVal instanceof Local : "these can be produced lazily" + curVal + "/" + phi; + operand = operandForInstruction(curVal); + } + resolver.move(operand, operandForPhi(phi)); + } + } + } + resolver.dispose(); + } + } + } + } + + /** + * Creates a new {@linkplain CiVariable variable}. + * + * @param kind the kind of the variable + * @return a new variable + */ + public CiVariable newVariable(CiKind kind) { + return operands.newVariable(kind); + } + + CiValue operandForInstruction(Value x) { + CiValue operand = x.operand(); + if (operand.isIllegal()) { + if (x instanceof Constant) { + x.setOperand(x.asConstant()); + } else { + assert x instanceof Phi || x instanceof Local : "only for Phi and Local"; + // allocate a variable for this local or phi + createResultVariable(x); + } + } + return x.operand(); + } + + private CiValue operandForPhi(Phi phi) { + assert !phi.isDead() : "dead phi: " + phi.id(); + if (phi.operand().isIllegal()) { + // allocate a variable for this phi + CiVariable operand = newVariable(phi.kind); + setResult(phi, operand); + } + return phi.operand(); + } + + protected void postGCWriteBarrier(CiValue addr, CiValue newVal) { + XirSnippet writeBarrier = xir.genWriteBarrier(toXirArgument(addr)); + if (writeBarrier != null) { + emitXir(writeBarrier, null, null, null, false); + } + } + + protected void preGCWriteBarrier(CiValue addrOpr, boolean patch, LIRDebugInfo info) { + } + + protected void setNoResult(Value x) { + x.clearOperand(); + } + + protected CiValue setResult(Value x, CiVariable operand) { + x.setOperand(operand); + if (C1XOptions.DetailedAsserts) { + operands.recordResult(operand, x); + } + return operand; + } + + protected void shiftOp(int code, CiValue resultOp, CiValue value, CiValue count, CiValue tmp) { + if (isTwoOperand && value != resultOp) { + assert count != resultOp : "malformed"; + lir.move(value, resultOp); + value = resultOp; + } + + assert count.isConstant() || count.isVariableOrRegister(); + switch (code) { + case ISHL: + case LSHL: + lir.shiftLeft(value, count, resultOp, tmp); + break; + case ISHR: + case LSHR: + lir.shiftRight(value, count, resultOp, tmp); + break; + case IUSHR: + case LUSHR: + lir.unsignedShiftRight(value, count, resultOp, tmp); + break; + default: + Util.shouldNotReachHere(); + } + } + + protected void walkState(Node x, FrameState state) { + if (state == null) { + return; + } + for (int index = 0; index < state.stackSize(); index++) { + Value value = state.stackAt(index); + if (value != x) { + walkStateValue(value); + } + } + for (int index = 0; index < state.localsSize(); index++) { + final Value value = state.localAt(index); + if (value != null) { + if (!(value instanceof Phi && ((Phi) value).isDead())) { + walkStateValue(value); + } + } + } + } + + private void walkStateValue(Value value) { + if (value != null) { + if (value instanceof Phi && !((Phi) value).isDead()) { + // phi's are special + operandForPhi((Phi) value); + } else if (value.operand().isIllegal()) { + // instruction doesn't have an operand yet + CiValue operand = makeOperand(value); + assert operand.isLegal() : "must be evaluated now"; + } + } + } + + protected LIRDebugInfo stateFor(Value x) { + assert lastState != null : "must have state before instruction for " + x; + return stateFor(x, lastState); + } + + protected LIRDebugInfo stateFor(Value x, FrameState state) { + if (compilation.placeholderState != null) { + state = compilation.placeholderState; + } + return new LIRDebugInfo(state); + } + + List visitInvokeArguments(CiCallingConvention cc, Invoke x, List pointerSlots) { + // for each argument, load it into the correct location + List argList = new ArrayList(x.argumentCount()); + int j = 0; + for (int i = 0; i < x.argumentCount(); i++) { + Value arg = x.argument(i); + if (arg != null) { + CiValue operand = cc.locations[j++]; + if (operand.isRegister()) { + force(arg, operand); + } else { + LIRItem param = new LIRItem(arg, this); + assert operand.isStackSlot(); + CiStackSlot slot = (CiStackSlot) operand; + assert !slot.inCallerFrame(); + param.loadForStore(slot.kind); + if (slot.kind == CiKind.Long || slot.kind == CiKind.Double) { + lir.unalignedMove(param.result(), slot); + } else { + lir.move(param.result(), slot); + } + + if (arg.kind == CiKind.Object && pointerSlots != null) { + // This slot must be marked explicitly in the pointer map. + pointerSlots.add(slot); + } + } + argList.add(operand); + } + } + return argList; + } + + /** + * Ensures that an operand has been {@linkplain Value#setOperand(CiValue) initialized} + * for storing the result of an instruction. + * + * @param instruction an instruction that produces a result value + */ + protected CiValue makeOperand(Value instruction) { + if (instruction == null) { + return CiValue.IllegalValue; + } + CiValue operand = instruction.operand(); + if (operand.isIllegal()) { + if (instruction instanceof Phi) { + // a phi may not have an operand yet if it is for an exception block + operand = operandForPhi((Phi) instruction); + } else if (instruction instanceof Constant) { + operand = operandForInstruction(instruction); + } + } + // the value must be a constant or have a valid operand + assert operand.isLegal() : "this root has not been visited yet; instruction=" + instruction; + return operand; + } + + /** + * Gets the ABI specific operand used to return a value of a given kind from a method. + * + * @param kind the kind of value being returned + * @return the operand representing the ABI defined location used return a value of kind {@code kind} + */ + protected CiValue resultOperandFor(CiKind kind) { + if (kind == CiKind.Void) { + return IllegalValue; + } + CiRegister returnRegister = compilation.registerConfig.getReturnRegister(kind); + return returnRegister.asValue(kind); + } + + protected XirSupport site(Value x) { + return xirSupport.site(x); + } + + public void maybePrintCurrentInstruction() { + if (currentInstruction != null && lastInstructionPrinted != currentInstruction) { + lastInstructionPrinted = currentInstruction; + InstructionPrinter ip = new InstructionPrinter(TTY.out()); + ip.printInstructionListing(currentInstruction); + } + } + + protected abstract boolean canInlineAsConstant(Value i); + + protected abstract boolean canStoreAsConstant(Value i, CiKind kind); + + protected abstract boolean strengthReduceMultiply(CiValue left, int constant, CiValue result, CiValue tmp); + + protected abstract CiAddress genAddress(CiValue base, CiValue index, int shift, int disp, CiKind kind); + + protected abstract void genCmpMemInt(Condition condition, CiValue base, int disp, int c, LIRDebugInfo info); + + protected abstract void genCmpRegMem(Condition condition, CiValue reg, CiValue base, int disp, CiKind kind, LIRDebugInfo info); + + /** + * Implements site-specific information for the XIR interface. + */ + static class XirSupport implements XirSite { + Value current; + + XirSupport() { + } + + public CiCodePos getCodePos() { + // TODO: get the code position of the current instruction if possible + return null; + } + + public boolean isNonNull(XirArgument argument) { + return false; + } + + public boolean requiresNullCheck() { + return current == null || true; + } + + public boolean requiresBoundsCheck() { + return true; + } + + public boolean requiresReadBarrier() { + return current == null || true; + } + + public boolean requiresWriteBarrier() { + return current == null || true; + } + + public boolean requiresArrayStoreCheck() { + return true; + } + + public RiType getApproximateType(XirArgument argument) { + return current == null ? null : current.declaredType(); + } + + public RiType getExactType(XirArgument argument) { + return current == null ? null : current.exactType(); + } + + XirSupport site(Value v) { + current = v; + return this; + } + + @Override + public String toString() { + return "XirSupport<" + current + ">"; + } + + + } + + @Override + public void visitFrameState(FrameState i) { + // nothing to do for now + } + + @Override + public void visitUnwind(Unwind x) { + // move exception oop into fixed register + CiCallingConvention callingConvention = compilation.frameMap().getCallingConvention(new CiKind[]{CiKind.Object}, RuntimeCall); + CiValue argumentOperand = callingConvention.locations[0]; + lir.move(makeOperand(x.exception()), argumentOperand); + List args = new ArrayList(1); + lir.callRuntime(CiRuntimeCall.UnwindException, CiValue.IllegalValue, args, null); + setNoResult(x); + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/LIRItem.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/LIRItem.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.gen; + +import com.oracle.max.graal.compiler.alloc.OperandPool.*; +import com.oracle.max.graal.compiler.ir.*; +import com.oracle.max.graal.compiler.util.*; +import com.sun.cri.ci.*; + +/** + * A helper utility for loading the {@linkplain Value#operand() result} + * of an instruction for use by another instruction. This helper takes + * into account the specifics of the consuming instruction such as whether + * it requires the input operand to be in memory or a register, any + * register size requirements of the input operand, and whether the + * usage has the side-effect of overwriting the input operand. To satisfy + * these constraints, an intermediate operand may be created and move + * instruction inserted to copy the output of the producer instruction + * into the intermediate operand. + * + * @author Marcelo Cintra + * @author Thomas Wuerthinger + * @author Doug Simon + */ +public class LIRItem { + + /** + * The instruction whose usage by another instruction is being modeled by this object. + * An instruction {@code x} uses instruction {@code y} if the {@linkplain Value#operand() result} + * of {@code y} is an input operand of {@code x}. + */ + public Value instruction; + + /** + * The LIR context of this helper object. + */ + private final LIRGenerator gen; + + /** + * The operand holding the result of this item's {@linkplain #instruction}. + */ + private CiValue resultOperand; + + /** + * Denotes if the use of the instruction's {@linkplain #resultOperand result operand} + * overwrites the value in the operand. That is, the use both uses and defines the + * operand. In this case, an {@linkplain #intermediateOperand intermediate operand} + * is created for the use so that other consumers of this item's {@linkplain #instruction} + * are not impacted. + */ + private boolean destructive; + + /** + * @see #destructive + */ + private CiValue intermediateOperand; + + public LIRItem(Value instruction, LIRGenerator gen) { + this.gen = gen; + this.instruction = instruction; + resultOperand = gen.makeOperand(instruction); + intermediateOperand = CiValue.IllegalValue; + } + + public void loadForStore(CiKind kind) { + if (gen.canStoreAsConstant(instruction, kind)) { + resultOperand = instruction.operand(); + if (!resultOperand.isConstant()) { + resultOperand = instruction.asConstant(); + } + } else if (kind == CiKind.Byte || kind == CiKind.Boolean) { + loadByteItem(); + } else { + loadItem(); + } + } + + public CiValue result() { + assert !destructive || !resultOperand.isRegister() : "shouldn't use setDestroysRegister with physical registers"; + if (destructive && (resultOperand.isVariable() || resultOperand.isConstant())) { + if (intermediateOperand.isIllegal()) { + intermediateOperand = gen.newVariable(instruction.kind); + gen.lir.move(resultOperand, intermediateOperand); + } + return intermediateOperand; + } else { + return resultOperand; + } + } + + public void setDestroysRegister() { + destructive = true; + } + + /** + * Determines if the operand is in a stack slot. + */ + public boolean isStack() { + return resultOperand.isAddress() || resultOperand.isStackSlot(); + } + + /** + * Determines if the operand is in a register or may be + * resolved to a register by the register allocator. + */ + public boolean isRegisterOrVariable() { + return resultOperand.isVariableOrRegister(); + } + + public void loadByteItem() { + if (gen.compilation.target.arch.isX86()) { + loadItem(); + CiValue res = result(); + + if (!res.isVariable() || !gen.operands.mustBeByteRegister(res)) { + // make sure that it is a byte register + assert !instruction.kind.isFloat() && !instruction.kind.isDouble() : "can't load floats in byte register"; + CiValue reg = gen.operands.newVariable(CiKind.Byte, VariableFlag.MustBeByteRegister); + gen.lir.move(res, reg); + resultOperand = reg; + } + } else if (gen.compilation.target.arch.isSPARC()) { + loadItem(); + } else { + Util.shouldNotReachHere(); + } + } + + public void loadNonconstant() { + assert gen.compilation.target.arch.isX86(); + CiValue r = instruction.operand(); + if (r.isConstant()) { + resultOperand = r; + } else { + loadItem(); + } + } + + private void setResult(CiVariable operand) { + gen.setResult(instruction, operand); + resultOperand = operand; + } + + /** + * Creates an operand containing the result of {@linkplain #instruction input instruction}. + */ + public void loadItem() { + if (result().isIllegal()) { + // update the item's result + resultOperand = instruction.operand(); + } + CiValue result = result(); + if (!result.isVariableOrRegister()) { + CiVariable operand; + operand = gen.newVariable(instruction.kind); + gen.lir.move(result, operand); + if (result.isConstant()) { + resultOperand = operand; + } else { + setResult(operand); + } + } + } + + @Override + public String toString() { + return result().toString(); + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/PhiResolver.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/PhiResolver.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,238 @@ +/* + * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.gen; + +import static com.sun.cri.ci.CiValue.*; + +import java.util.*; + +import com.oracle.max.graal.compiler.ir.*; +import com.sun.cri.ci.*; + +/** + * Converts {@link Phi} instructions into moves. + * + * Resolves cycles: + *
+ *
+ *  r1 := r2  becomes  temp := r1
+ *  r2 := r1           r1 := r2
+ *                     r2 := temp
+ * 
+ * + * and orders moves: + * + *
+ *  r2 := r3  becomes  r1 := r2
+ *  r1 := r2           r2 := r3
+ * 
+ * + * @author Marcelo Cintra + * @author Thomas Wuerthinger + * @author Doug Simon + */ +public class PhiResolver { + + /** + * Tracks a data flow dependency between a source operand and any number of the destination operands. + */ + static class Node { + + /** + * A source operand whose value flows into the {@linkplain #destinations destination} operands. + */ + final CiValue operand; + + /** + * The operands whose values are defined by the {@linkplain #operand source} operand. + */ + final ArrayList destinations; + + /** + * Denotes if a move instruction has already been emitted to initialize the value of {@link #operand}. + */ + boolean assigned; + + /** + * Specifies if this operand been visited for the purpose of emitting a move instruction. + */ + boolean visited; + + /** + * Specifies if this is the initial definition in data flow path for a given value. + */ + boolean startNode; + + Node(CiValue operand) { + this.operand = operand; + destinations = new ArrayList(4); + } + + @Override + public String toString() { + StringBuilder buf = new StringBuilder(operand.toString()); + if (!destinations.isEmpty()) { + buf.append(" ->"); + for (Node node : destinations) { + buf.append(' ').append(node.operand); + } + } + return buf.toString(); + } + } + + private final LIRGenerator gen; + + /** + * The operand loop header phi for the operand currently being process in {@link #dispose()}. + */ + private Node loop; + + private CiValue temp; + + private final ArrayList variableOperands = new ArrayList(3); + private final ArrayList otherOperands = new ArrayList(3); + + /** + * Maps operands to nodes. + */ + private final HashMap operandToNodeMap = new HashMap(); + + public PhiResolver(LIRGenerator gen) { + this.gen = gen; + temp = IllegalValue; + } + + public void dispose() { + // resolve any cycles in moves from and to variables + for (int i = variableOperands.size() - 1; i >= 0; i--) { + Node node = variableOperands.get(i); + if (!node.visited) { + loop = null; + move(null, node); + node.startNode = true; + assert temp.isIllegal() : "moveTempTo() call missing"; + } + } + + // generate move for move from non variable to arbitrary destination + for (int i = otherOperands.size() - 1; i >= 0; i--) { + Node node = otherOperands.get(i); + for (int j = node.destinations.size() - 1; j >= 0; j--) { + emitMove(node.operand, node.destinations.get(j).operand); + } + } + } + + public void move(CiValue src, CiValue dest) { + assert dest.isVariable() : "destination must be virtual"; + // tty.print("move "); src.print(); tty.print(" to "); dest.print(); tty.cr(); + assert src.isLegal() : "source for phi move is illegal"; + assert dest.isLegal() : "destination for phi move is illegal"; + Node srcNode = sourceNode(src); + Node destNode = destinationNode(dest); + srcNode.destinations.add(destNode); + } + + private Node createNode(CiValue operand, boolean source) { + Node node; + if (operand.isVariable()) { + node = operandToNodeMap.get(operand); + assert node == null || node.operand.equals(operand); + if (node == null) { + node = new Node(operand); + operandToNodeMap.put(operand, node); + } + // Make sure that all variables show up in the list when + // they are used as the source of a move. + if (source) { + if (!variableOperands.contains(node)) { + variableOperands.add(node); + } + } + } else { + assert source; + node = new Node(operand); + otherOperands.add(node); + } + return node; + } + + private Node destinationNode(CiValue opr) { + return createNode(opr, false); + } + + private void emitMove(CiValue src, CiValue dest) { + assert src.isLegal(); + assert dest.isLegal(); + gen.lir.move(src, dest); + } + + // Traverse assignment graph in depth first order and generate moves in post order + // ie. two assignments: b := c, a := b start with node c: + // Call graph: move(NULL, c) -> move(c, b) -> move(b, a) + // Generates moves in this order: move b to a and move c to b + // ie. cycle a := b, b := a start with node a + // Call graph: move(NULL, a) -> move(a, b) -> move(b, a) + // Generates moves in this order: move b to temp, move a to b, move temp to a + private void move(Node src, Node dest) { + if (!dest.visited) { + dest.visited = true; + for (int i = dest.destinations.size() - 1; i >= 0; i--) { + move(dest, dest.destinations.get(i)); + } + } else if (!dest.startNode) { + // cycle in graph detected + assert loop == null : "only one loop valid!"; + loop = dest; + moveToTemp(src.operand); + return; + } // else dest is a start node + + if (!dest.assigned) { + if (loop == dest) { + moveTempTo(dest.operand); + dest.assigned = true; + } else if (src != null) { + emitMove(src.operand, dest.operand); + dest.assigned = true; + } + } + } + + private void moveTempTo(CiValue dest) { + assert temp.isLegal(); + emitMove(temp, dest); + temp = IllegalValue; + } + + private void moveToTemp(CiValue src) { + assert temp.isIllegal(); + temp = gen.newVariable(src.kind); + emitMove(src, temp); + } + + private Node sourceNode(CiValue opr) { + return createNode(opr, true); + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/PhiSimplifier.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/PhiSimplifier.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.gen; + +import com.oracle.max.graal.compiler.ir.*; +import com.oracle.max.graal.graph.*; + +/** + * The {@code PhiSimplifier} class is a helper class that can reduce phi instructions. + */ +public final class PhiSimplifier { + + private NodeBitMap visited; + private NodeBitMap cannotSimplify; + + public PhiSimplifier(Graph graph) { + visited = graph.createNodeBitMap(); + cannotSimplify = graph.createNodeBitMap(); + + for (Node n : graph.getNodes()) { + if (n instanceof Phi) { + simplify((Phi) n); + } + } + } + + private Value simplify(Value x) { + if (x == null || !(x instanceof Phi)) { + return x; + } + Phi phi = (Phi) x; + + if (phi.valueCount() == 1 && !cannotSimplify.isMarked(phi)) { + return (Value) phi.replace(phi.valueAt(0)); + } + + if (cannotSimplify.isMarked(phi)) { + // already tried, cannot simplify this phi + return phi; + } else if (visited.isMarked(phi)) { + // break cycles in phis + return phi; + } else if (phi.isDead()) { + // don't bother with illegals + return phi; + } else { + // attempt to simplify the phi by recursively simplifying its operands + visited.mark(phi); + Value phiSubst = null; + int max = phi.valueCount(); + boolean cannotSimplify = false; + for (int i = 0; i < max; i++) { + Value oldInstr = phi.valueAt(i); + + if (oldInstr == null || (oldInstr instanceof Phi && ((Phi) oldInstr).isDead())) { + // if one operand is illegal, make the entire phi illegal + phi.makeDead(); + visited.clear(phi); + return phi; + } + + Value newInstr = simplify(oldInstr); + + if (newInstr == null || (newInstr instanceof Phi && ((Phi) newInstr).isDead())) { + // if the subst instruction is illegal, make the entire phi illegal + phi.makeDead(); + visited.clear(phi); + return phi; + } + + // attempt to simplify this operand + if (!cannotSimplify) { + + if (newInstr != phi && newInstr != phiSubst) { + if (phiSubst == null) { + phiSubst = newInstr; + continue; + } + // this phi cannot be simplified + cannotSimplify = true; + } + } + } + if (cannotSimplify) { + this.cannotSimplify.mark(phi); + visited.clear(phi); + return phi; + } + + // successfully simplified the phi + assert phiSubst != null : "illegal phi function"; + visited.clear(phi); + + phi.replace(phiSubst); + + return phiSubst; + } + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/package-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/package-info.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +/** + * This package contains the port of the LIRGenerator which translates + * HIR instructions to LIR instructions for the backend. + * + * @author Marcelo Cintra + * @author Thomas Wuerthinger + */ +package com.oracle.max.graal.compiler.gen; diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/globalstub/GlobalStub.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/globalstub/GlobalStub.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.globalstub; + +import static com.sun.cri.ci.CiKind.*; + +import com.sun.cri.ci.*; + +/** + * A global stub is a shared routine that performs an operation on behalf of compiled code. + * Typically the routine is too large to inline, is infrequent, or requires runtime support. + * Global stubs are called with a callee-save convention; the global stub must save any + * registers it may destroy and then restore them upon return. This allows the register + * allocator to ignore calls to global stubs. Parameters to global stubs are + * passed on the stack in order to preserve registers for the rest of the code. + * + * @author Thomas Wuerthinger + * @author Ben L. Titzer + */ +public class GlobalStub { + + public enum Id { + + fneg(Float, Float), + dneg(Double, Double), + f2i(Int, Float), + f2l(Long, Float), + d2i(Int, Double), + d2l(Long, Double); + + public final CiKind resultKind; + public final CiKind[] arguments; + + private Id(CiKind resultKind, CiKind... args) { + this.resultKind = resultKind; + this.arguments = args; + } + } + + public final Id id; + public final CiKind resultKind; + public final Object stubObject; + public final int argsSize; + public final int[] argOffsets; + public final int resultOffset; + + public GlobalStub(Id id, CiKind resultKind, Object stubObject, int argsSize, int[] argOffsets, int resultOffset) { + this.id = id; + this.resultKind = resultKind; + this.stubObject = stubObject; + this.argsSize = argsSize; + this.argOffsets = argOffsets; + this.resultOffset = resultOffset; + } + +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/globalstub/GlobalStubEmitter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/globalstub/GlobalStubEmitter.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.globalstub; + +import com.sun.cri.ci.*; +import com.sun.cri.ri.*; +import com.sun.cri.xir.*; + +/** + * An interface to represent the entity that generates stubs. + * + * @author Thomas Wuerthinger + * @author Ben L. Titzer + */ +public interface GlobalStubEmitter { + GlobalStub emit(GlobalStub.Id stub, RiRuntime runtime); + GlobalStub emit(CiRuntimeCall runtimeCall, RiRuntime runtime); + GlobalStub emit(XirTemplate t, RiRuntime runtime); +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/graph/BlockMap.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/graph/BlockMap.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,664 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.graph; + +import static com.sun.cri.bytecode.Bytecodes.*; + +import java.util.*; + +import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.compiler.ir.*; +import com.sun.cri.bytecode.*; +import com.sun.cri.ci.*; +import com.sun.cri.ri.*; + +/** + * Builds a mapping between bytecodes and basic blocks and builds a conservative control flow + * graph. Note that this class serves a similar role to C1's {@code BlockListBuilder}, but makes fewer assumptions about + * what the compiler interface provides. It builds all basic blocks for the control flow graph without requiring the + * compiler interface to provide a bitmap of the beginning of basic blocks. It makes two linear passes; one over the + * bytecodes to build block starts and successor lists, and one pass over the block map to build the CFG. + * + * Note that the CFG built by this class is not connected to the actual {@code BlockBegin} instances; this class + * does, however, compute and assign the reverse postorder number of the blocks. This comment needs refinement. (MJJ) + * + *

More Details on {@link BlockMap#build}

+ * + * If the method has any exception handlers the {@linkplain #exceptionMap exception map} will be created (TBD). + * + * The bytecodes are then scanned linearly looking for bytecodes that contain control transfers, e.g., {@code GOTO}, + * {@code RETURN}, {@code IFGE}, and creating the corresponding entries in {@link #successorMap} and {@link #blockMap}. + * In addition, if {@link #exceptionMap} is not null, entries are made for any bytecode that can cause an exception. + * More TBD. + * + * Observe that this process finds bytecodes that terminate basic blocks, so the {@link #moveSuccessorLists} method is + * called to reassign the successors to the {@code BlockBegin} node that actually starts the block. + * + *

Example

+ * + * Consider the following source code: + * + *
+ * 
+ *     public static int test(int arg1, int arg2) {
+ *         int x = 0;
+ *         while (arg2 > 0) {
+ *             if (arg1 > 0) {
+ *                 x += 1;
+ *             } else if (arg1 < 0) {
+ *                 x -= 1;
+ *             }
+ *         }
+ *         return x;
+ *     }
+ * 
+ * 
+ * + * This is translated by javac to the following bytecode: + * + *
+ * 
+ *    0:   iconst_0
+ *    1:   istore_2
+ *    2:   goto    22
+ *    5:   iload_0
+ *    6:   ifle    15
+ *    9:   iinc    2, 1
+ *    12:  goto    22
+ *    15:  iload_0
+ *    16:  ifge    22
+ *    19:  iinc    2, -1
+ *    22:  iload_1
+ *    23:  ifgt    5
+ *    26:  iload_2
+ *    27:  ireturn
+ *    
+ * 
+ * + * There are seven basic blocks in this method, 0..2, 5..6, 9..12, 15..16, 19..19, 22..23 and 26..27. Therefore, before + * the call to {@code moveSuccessorLists}, the {@code blockMap} array has {@code BlockBegin} nodes at indices 0, 5, 9, + * 15, 19, 22 and 26. The {@code successorMap} array has entries at 2, 6, 12, 16, 23, 27 corresponding to the control + * transfer bytecodes. The entry at index 6, for example, is a length two array of {@code BlockBegin} nodes for indices + * 9 and 15, which are the successors for the basic block 5..6. After the call to {@code moveSuccessors}, {@code + * successorMap} has entries at 0, 5, 9, 15, 19, 22 and 26, i.e, matching {@code blockMap}. + *

+ * Next the blocks are numbered using reverse + * post-order. For the above example this results in the numbering 2, 4, 7, 5, 6, 3, 8. Also loop header blocks are + * detected during the traversal by detecting a repeat visit to a block that is still being processed. This causes the + * block to be flagged as a loop header and also added to the {@link #loopBlocks} list. The {@code loopBlocks} list + * contains the blocks at 0, 5, 9, 15, 19, 22, with 22 as the loop header. (N.B. the loop header block is added multiple + * (4) times to this list). (Should 0 be in? It's not inside the loop). + * + * If the {@code computeStoresInLoops} argument to {@code build} is true, the {@code loopBlocks} list is processed to + * mark all local variables that are stored in the blocks in the list. + */ +public final class BlockMap { + public static class Block { + public int startBci; + public int endBci; + public boolean isExceptionEntry; + public boolean isLoopHeader; + public int blockID; + + public Instruction firstInstruction; + + final HashSet successors = new HashSet(); + private boolean visited; + private boolean active; + private int loops; + } + + public static class ExceptionBlock extends Block { + public RiExceptionHandler handler; + public Block next; + } + + private static final Block[] NO_SUCCESSORS = new Block[0]; + + /** + * The blocks found in this method, in reverse postorder. + */ + public final List blocks; + + /** + * A bit map covering the locals with a bit set for each local that might be stored to within a + * loop. If the bit is cleared, it is guaranteed that the local is never stored in a loop. + */ + public final BitSet storesInLoops; + + private final RiMethod method; + + private Block[] blockMap; + + private BitSet canTrap; + + /** + * Creates a new BlockMap instance from bytecode of the given method . + * @param method the compiler interface method containing the code + */ + public BlockMap(RiMethod method) { + this.method = method; + this.blockMap = new Block[method.code().length]; + if (method.exceptionHandlers().length != 0) { + this.canTrap = new BitSet(blockMap.length); + } + this.blocks = new ArrayList(); + this.storesInLoops = new BitSet(method.maxLocals()); + } + + /** + * Builds the block map and conservative CFG and numbers blocks. + */ + public void build() { + makeExceptionEntries(); + iterateOverBytecodes(); + addExceptionEdges(); + computeBlockOrder(); + + initializeBlockIds(); + + // Discard big arrays so that they can be GCed + blockMap = null; + canTrap = null; + } + + private void initializeBlockIds() { + for (int i = 0; i < blocks.size(); i++) { + blocks.get(i).blockID = i; + } + } + + private void makeExceptionEntries() { + // start basic blocks at all exception handler blocks and mark them as exception entries + for (RiExceptionHandler h : method.exceptionHandlers()) { + Block xhandler = makeBlock(h.handlerBCI()); + xhandler.isExceptionEntry = true; + } + } + + private void iterateOverBytecodes() { + // iterate over the bytecodes top to bottom. + // mark the entrypoints of basic blocks and build lists of successors for + // all bytecodes that end basic blocks (i.e. goto, ifs, switches, throw, jsr, returns, ret) + byte[] code = method.code(); + Block current = null; + int bci = 0; + while (bci < code.length) { + if (current == null || blockMap[bci] != null) { + Block b = makeBlock(bci); + if (current != null) { + setSuccessors(current.endBci, b); + } + current = b; + } + blockMap[bci] = current; + current.endBci = bci; + + int opcode = Bytes.beU1(code, bci); + switch (opcode) { + case IRETURN: // fall through + case LRETURN: // fall through + case FRETURN: // fall through + case DRETURN: // fall through + case ARETURN: // fall through + case WRETURN: // fall through + case RETURN: { + current = null; + + assert lengthOf(code, bci) == 1; + bci += 1; + break; + } + + case ATHROW: { + current = null; + if (canTrap != null) { + canTrap.set(bci); + } + + assert lengthOf(code, bci) == 1; + bci += 1; + break; + } + + case IFEQ: // fall through + case IFNE: // fall through + case IFLT: // fall through + case IFGE: // fall through + case IFGT: // fall through + case IFLE: // fall through + case IF_ICMPEQ: // fall through + case IF_ICMPNE: // fall through + case IF_ICMPLT: // fall through + case IF_ICMPGE: // fall through + case IF_ICMPGT: // fall through + case IF_ICMPLE: // fall through + case IF_ACMPEQ: // fall through + case IF_ACMPNE: // fall through + case IFNULL: // fall through + case IFNONNULL: { + current = null; + Block b1 = makeBlock(bci + 3); + Block b2 = makeBlock(bci + Bytes.beS2(code, bci + 1)); + setSuccessors(bci, b1, b2); + + assert lengthOf(code, bci) == 3; + bci += 3; + break; + } + + case GOTO: { + current = null; + Block b1 = makeBlock(bci + Bytes.beS2(code, bci + 1)); + setSuccessors(bci, b1); + + assert lengthOf(code, bci) == 3; + bci += 3; + break; + } + + case GOTO_W: { + current = null; + Block b1 = makeBlock(bci + Bytes.beS4(code, bci + 1)); + setSuccessors(bci, b1); + + assert lengthOf(code, bci) == 5; + bci += 5; + break; + } + + case TABLESWITCH: { + BytecodeTableSwitch sw = new BytecodeTableSwitch(code, bci); + setSuccessors(bci, makeSwitchSuccessors(sw)); + current = null; + + assert lengthOf(code, bci) == sw.size(); + bci += sw.size(); + break; + } + + case LOOKUPSWITCH: { + current = null; + BytecodeLookupSwitch sw = new BytecodeLookupSwitch(code, bci); + setSuccessors(bci, makeSwitchSuccessors(sw)); + + assert lengthOf(code, bci) == sw.size(); + bci += sw.size(); + break; + } + + case JSR: { + throw new JSRNotSupportedBailout(); + } + case JSR_W: { + throw new JSRNotSupportedBailout(); + } + case RET: { + throw new JSRNotSupportedBailout(); + } + + case WIDE: { + bci += lengthOf(code, bci); + break; + } + + default: { + if (canTrap != null && canTrap(opcode)) { + canTrap.set(bci); + } + + assert lengthOf(code, bci) == lengthOf(opcode); + bci += lengthOf(opcode); + } + } + } + } + + public static boolean canTrap(int opcode) { + switch (opcode) { + case INVOKESTATIC: + case INVOKESPECIAL: + case INVOKEVIRTUAL: + case INVOKEINTERFACE: { + return true; + } + } + return false; + } + + private Block makeBlock(int startBci) { + Block oldBlock = blockMap[startBci]; + if (oldBlock == null) { + Block newBlock = new Block(); + newBlock.startBci = startBci; + blockMap[startBci] = newBlock; + return newBlock; + + } else if (oldBlock.startBci != startBci) { + // Backward branch into the middle of an already processed block. + // Add the correct fall-through successor. + Block newBlock = new Block(); + newBlock.startBci = startBci; + newBlock.endBci = oldBlock.endBci; + newBlock.successors.addAll(oldBlock.successors); + + oldBlock.endBci = startBci - 1; + oldBlock.successors.clear(); + oldBlock.successors.add(newBlock); + + for (int i = startBci; i <= newBlock.endBci; i++) { + blockMap[i] = newBlock; + } + return newBlock; + + } else { + return oldBlock; + } + } + + private Block[] makeSwitchSuccessors(BytecodeSwitch tswitch) { + int max = tswitch.numberOfCases(); + Block[] successors = new Block[max + 1]; + for (int i = 0; i < max; i++) { + successors[i] = makeBlock(tswitch.targetAt(i)); + } + successors[max] = makeBlock(tswitch.defaultTarget()); + return successors; + } + + private void setSuccessors(int predBci, Block... successors) { + for (Block sux : successors) { + if (sux.isExceptionEntry) { + throw new CiBailout("Exception handler can be reached by both normal and exceptional control flow"); + } + } + Block predecessor = blockMap[predBci]; + assert predecessor.successors.size() == 0; + predecessor.successors.addAll(Arrays.asList(successors)); + } + + private HashMap exceptionDispatch = new HashMap(); + + private ExceptionBlock unwindBlock; + + private Block makeExceptionDispatch(List handlers, int index) { + RiExceptionHandler handler = handlers.get(index); + if (handler.isCatchAll()) { + return blockMap[handler.handlerBCI()]; + } + ExceptionBlock block = exceptionDispatch.get(handler); + if (block == null) { + block = new ExceptionBlock(); + block.startBci = -1; + block.endBci = -1; + block.handler = handler; + block.successors.add(blockMap[handler.handlerBCI()]); + if (index < handlers.size() - 1) { + block.next = makeExceptionDispatch(handlers, index + 1); + block.successors.add(block.next); + } + exceptionDispatch.put(handler, block); + } + return block; + } + + private void addExceptionEdges() { + if (canTrap == null) { + return; + } + + for (int bci = canTrap.nextSetBit(0); bci >= 0; bci = canTrap.nextSetBit(bci + 1)) { + Block block = blockMap[bci]; + + ArrayList handlers = null; + for (RiExceptionHandler h : method.exceptionHandlers()) { + if (h.startBCI() <= bci && bci < h.endBCI()) { + if (handlers == null) { + handlers = new ArrayList(); + } + handlers.add(h); + if (h.isCatchAll()) { + break; + } + } + } + if (handlers != null) { + Block dispatch = makeExceptionDispatch(handlers, 0); + block.successors.add(dispatch); + } + } + } + + private void computeBlockOrder() { + int loop = computeBlockOrder(blockMap[0]); + + if (loop != 0) { + // There is a path from a loop end to the method entry that does not pass the loop header. + // Therefore, the loop is non reducible (has more than one entry). + // We don't want to compile such methods because the IR only supports structured loops. + throw new CiBailout("Non-reducible loop"); + } + + // Convert postorder to the desired reverse postorder. + Collections.reverse(blocks); + } + + /** + * The next available loop number. + */ + private int nextLoop = 0; + + /** + * Mark the block as a loop header, using the next available loop number. + * Also checks for corner cases that we don't want to compile. + */ + private void makeLoopHeader(Block block) { + if (!block.isLoopHeader) { + block.isLoopHeader = true; + + if (block.isExceptionEntry) { + // Loops that are implicitly formed by an exception handler lead to all sorts of corner cases. + // Don't compile such methods for now, until we see a concrete case that allows checking for correctness. + throw new CiBailout("Loop formed by an exception handler"); + } + if (nextLoop >= Integer.SIZE) { + // This restriction can be removed by using a fall-back to a BitSet in case we have more than 32 loops + // Don't compile such methods for now, until we see a concrete case that allows checking for correctness. + throw new CiBailout("Too many loops in method"); + } + + assert block.loops == 0; + block.loops = 1 << nextLoop; + nextLoop++; + } + assert Integer.bitCount(block.loops) == 1; + } + + /** + * Depth-first traversal of the control flow graph. The flag {@linkplain Block#visited} is used to + * visit every block only once. The flag {@linkplain Block#active} is used to detect cycles (backward + * edges). + */ + private int computeBlockOrder(Block block) { + if (block.visited) { + if (block.active) { + // Reached block via backward branch. + makeLoopHeader(block); + } + // Return cached loop information for this block. + return block.loops; + } + + block.visited = true; + block.active = true; + + int loops = 0; + for (Block successor : block.successors) { + // Recursively process successors. + loops |= computeBlockOrder(successor); + } + + if (loops != 0) { + processLoopBlock(block); + } + if (block.isLoopHeader) { + assert Integer.bitCount(block.loops) == 1; + loops &= ~block.loops; + } + + block.loops = loops; + block.active = false; + blocks.add(block); + + return loops; + } + + private void processLoopBlock(Block block) { + // process all the stores in this block + byte[] code = method.code(); + int bci = block.startBci; + if (bci >= 0) { + while (bci <= block.endBci) { + int opcode = Bytes.beU1(code, bci); + if (isStore(opcode)) { + processStore(opcode, Bytes.beU1(code, bci + 1)); + + } else if (opcode == WIDE) { + opcode = Bytes.beU1(code, bci + 1); + if (isStore(opcode)) { + processStore(opcode, Bytes.beU2(code, bci + 2)); + } + } + bci += lengthOf(code, bci); + } + } + } + + private void processStore(int opcode, int local) { + switch (opcode) { + case IINC: + case ISTORE: + case FSTORE: + case WSTORE: + case ASTORE: + storesInLoops.set(local); + break; + + case LSTORE: + case DSTORE: + storesInLoops.set(local); + storesInLoops.set(local + 1); + break; + + case ISTORE_0: + case FSTORE_0: + case ASTORE_0: + case WSTORE_0: + storesInLoops.set(0); + break; + case ISTORE_1: + case FSTORE_1: + case ASTORE_1: + case WSTORE_1: + storesInLoops.set(1); + break; + case ISTORE_2: + case FSTORE_2: + case ASTORE_2: + case WSTORE_2: + storesInLoops.set(2); + break; + case ISTORE_3: + case FSTORE_3: + case ASTORE_3: + case WSTORE_3: + storesInLoops.set(3); + break; + + case LSTORE_0: + case DSTORE_0: + storesInLoops.set(0); + storesInLoops.set(1); + break; + case LSTORE_1: + case DSTORE_1: + storesInLoops.set(1); + storesInLoops.set(2); + break; + case LSTORE_2: + case DSTORE_2: + storesInLoops.set(2); + storesInLoops.set(3); + break; + case LSTORE_3: + case DSTORE_3: + storesInLoops.set(3); + storesInLoops.set(4); + break; + + default: + throw new InternalError("undefined store bytecode"); + } + } + + + + /** + * Print block information in the format required by {@linkplain CFGPrinter}. The method must + * be here because it accesses private state of a block. + */ + public void printBlock(Block block, LogStream out) { + out.print("name \"B").print(block.startBci).println('"'); + out.print("from_bci ").println(block.startBci); + out.print("to_bci ").println(block.endBci); + + out.println("predecessors "); + + out.print("successors "); + for (Block succ : block.successors) { + if (!succ.isExceptionEntry) { + out.print("\"B").print(succ.startBci).print("\" "); + } + } + out.println(); + + out.print("xhandlers"); + for (Block succ : block.successors) { + if (succ.isExceptionEntry) { + out.print("\"B").print(succ.startBci).print("\" "); + } + } + out.println(); + + out.print("flags "); + if (block.isExceptionEntry) { + out.print("\"ex\" "); + } + if (block.isLoopHeader) { + out.print("\"plh\" "); + } + out.println(); + + out.print("loop_depth ").println(Integer.bitCount(block.loops)); + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/graph/CompilerGraph.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/graph/CompilerGraph.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.graph; + +import com.oracle.max.graal.compiler.ir.*; +import com.oracle.max.graal.graph.*; + + +public class CompilerGraph extends Graph { + + private Return returnSingleton; + private Unwind unwindSingleton; + + public Return createReturn(Value result) { + assert returnSingleton == null; + returnSingleton = new Return(result, this); + return returnSingleton; + } + + public Return getReturn() { + return returnSingleton; + } + + public Unwind createUnwind(Value exception) { + assert unwindSingleton == null; + unwindSingleton = new Unwind(exception, this); + return unwindSingleton; + } + + public Unwind getUnwind() { + return unwindSingleton; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/graph/DeadCodeElimination.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/graph/DeadCodeElimination.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.graph; + +import com.oracle.max.graal.compiler.*; +import com.oracle.max.graal.compiler.gen.*; +import com.oracle.max.graal.compiler.ir.*; +import com.oracle.max.graal.graph.*; + + +public class DeadCodeElimination extends Phase { + + private NodeBitMap alive; + private NodeWorklist worklist; + private Graph graph; + + public int deletedNodeCount; + + @Override + protected void run(Graph graph) { + this.graph = graph; + this.alive = graph.createNodeBitMap(); + this.worklist = graph.createNodeWorklist(); + + worklist.add(graph.start()); + + iterateSuccessors(); + disconnectCFGNodes(); + + iterateInputs(); + disconnectNonCFGNodes(); + + deleteCFGNodes(); + deleteNonCFGNodes(); + + new PhiSimplifier(graph); + + if (C1XOptions.TraceDeadCodeElimination) { + System.out.printf("dead code elimination: deleted %d nodes\n", deletedNodeCount); + } + } + + private static boolean isCFG(Node n) { + return n != null && ((n instanceof Instruction) || n == n.graph().start()); + } + + private void iterateSuccessors() { + for (Node current : worklist) { + for (Node successor : current.successors()) { + worklist.add(successor); + } + } + } + + private void disconnectCFGNodes() { + for (Node node : graph.getNodes()) { + if (node != Node.Null && !worklist.isMarked(node) && isCFG(node)) { + // iterate backwards so that the predecessor indexes in removePhiPredecessor are correct + for (int i = node.successors().size() - 1; i >= 0; i--) { + Node successor = node.successors().get(i); + if (successor != Node.Null && worklist.isMarked(successor)) { + if (successor instanceof Merge) { + ((Merge) successor).removePhiPredecessor(node); + } + } + } + node.successors().clearAll(); + node.inputs().clearAll(); + } + } + } + + private void deleteCFGNodes() { + for (Node node : graph.getNodes()) { + if (node != Node.Null && !worklist.isMarked(node) && isCFG(node)) { + node.delete(); + deletedNodeCount++; + } + } + } + + private void iterateInputs() { + for (Node node : graph.getNodes()) { + if (node != Node.Null && worklist.isMarked(node)) { + for (Node input : node.inputs()) { + worklist.add(input); + } + } + } + for (Node current : worklist) { + for (Node input : current.inputs()) { + worklist.add(input); + } + } + } + + private void disconnectNonCFGNodes() { + for (Node node : graph.getNodes()) { + if (node != Node.Null && !worklist.isMarked(node) && !isCFG(node)) { + node.inputs().clearAll(); + } + } + } + + private void deleteNonCFGNodes() { + for (Node node : graph.getNodes()) { + if (node != Node.Null && !worklist.isMarked(node) && !isCFG(node)) { + node.delete(); + deletedNodeCount++; + } + } + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/graph/GraphBuilder.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/graph/GraphBuilder.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,1521 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.graph; + +import static com.sun.cri.bytecode.Bytecodes.*; +import static java.lang.reflect.Modifier.*; + +import java.lang.reflect.*; +import java.util.*; + +import com.oracle.max.graal.compiler.*; +import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.compiler.graph.BlockMap.*; +import com.oracle.max.graal.compiler.graph.BlockMap.Block; +import com.oracle.max.graal.compiler.ir.*; +import com.oracle.max.graal.compiler.schedule.*; +import com.oracle.max.graal.compiler.util.*; +import com.oracle.max.graal.compiler.value.*; +import com.oracle.max.graal.graph.*; +import com.sun.cri.bytecode.*; +import com.sun.cri.ci.*; +import com.sun.cri.ri.*; +import com.sun.cri.ri.RiType.*; + +/** + * The {@code GraphBuilder} class parses the bytecode of a method and builds the IR graph. + * A number of optimizations may be performed during parsing of the bytecode, including value + * numbering, inlining, constant folding, strength reduction, etc. + */ +public final class GraphBuilder { + + /** + * The minimum value to which {@link C1XOptions#TraceBytecodeParserLevel} must be set to trace + * the bytecode instructions as they are parsed. + */ + public static final int TRACELEVEL_INSTRUCTIONS = 1; + + /** + * The minimum value to which {@link C1XOptions#TraceBytecodeParserLevel} must be set to trace + * the frame state before each bytecode instruction as it is parsed. + */ + public static final int TRACELEVEL_STATE = 2; + + private final C1XCompilation compilation; + private final CompilerGraph graph; + + private final CiStatistics stats; + private final RiRuntime runtime; + private final RiMethod method; + private final RiConstantPool constantPool; + + private final BytecodeStream stream; // the bytecode stream + private final LogStream log; + private final FrameStateBuilder frameState; // the current execution state + + // bci-to-block mapping + private Block[] blockFromBci; + private ArrayList blockList; + + private int nextBlockNumber; + + private Value methodSynchronizedObject; + private CiExceptionHandler syncHandler; + + private Block unwindBlock; + private Block returnBlock; + + // the worklist of blocks, sorted by depth first number + private final PriorityQueue workList = new PriorityQueue(10, new Comparator() { + public int compare(Block o1, Block o2) { + return o1.blockID - o2.blockID; + } + }); + + private Instruction lastInstr; // the last instruction added + + private final Set blocksOnWorklist = new HashSet(); + private final Set blocksVisited = new HashSet(); + + + /** + * Creates a new, initialized, {@code GraphBuilder} instance for a given compilation. + * + * @param compilation the compilation + * @param ir the IR to build the graph into + * @param graph + */ + public GraphBuilder(C1XCompilation compilation, RiMethod method, CompilerGraph graph) { + this.compilation = compilation; + this.graph = graph; + + this.runtime = compilation.runtime; + this.method = method; + this.stats = compilation.stats; + this.log = C1XOptions.TraceBytecodeParserLevel > 0 ? new LogStream(TTY.out()) : null; + this.stream = new BytecodeStream(method.code()); + + this.constantPool = runtime.getConstantPool(method); + this.frameState = new FrameStateBuilder(method, graph); + } + + /** + * Builds the graph for a the specified {@code IRScope}. + * + * @param createUnwind setting this to true will always generate an unwind block, even if there is no exception + * handler and the method is not synchronized + */ + public void build(boolean createUnwind) { + if (log != null) { + log.println(); + log.println("Compiling " + method); + } + + // 2. compute the block map, setup exception handlers and get the entrypoint(s) + BlockMap blockMap = compilation.getBlockMap(method); + + blockList = new ArrayList(blockMap.blocks); + blockFromBci = new Block[method.code().length]; + for (int i = 0; i < blockList.size(); i++) { + int blockID = nextBlockNumber(); + assert blockID == i; + Block block = blockList.get(i); + if (block.startBci >= 0) { + blockFromBci[block.startBci] = block; + } + } + + // 1. create the start block + Block startBlock = nextBlock(Instruction.SYNCHRONIZATION_ENTRY_BCI); + markOnWorkList(startBlock); + lastInstr = createTarget(startBlock, frameState); + graph.start().setStart(lastInstr); + + if (isSynchronized(method.accessFlags())) { + // 4A.1 add a monitor enter to the start block + methodSynchronizedObject = synchronizedObject(frameState, method); + genMonitorEnter(methodSynchronizedObject, Instruction.SYNCHRONIZATION_ENTRY_BCI); + // 4A.2 finish the start block + finishStartBlock(startBlock); + + // 4A.3 setup an exception handler to unlock the root method synchronized object + syncHandler = new CiExceptionHandler(0, method.code().length, Instruction.SYNCHRONIZATION_ENTRY_BCI, 0, null); + } else { + // 4B.1 simply finish the start block + finishStartBlock(startBlock); + + if (createUnwind) { + syncHandler = new CiExceptionHandler(0, method.code().length, Instruction.SYNCHRONIZATION_ENTRY_BCI, 0, null); + } + } + + // 5. SKIPPED: look for intrinsics + + // 6B.1 do the normal parsing + addToWorkList(blockFromBci[0]); + iterateAllBlocks(); + + // remove Placeholders + for (Node n : graph.getNodes()) { + if (n instanceof Placeholder) { + Placeholder p = (Placeholder) n; + assert p.blockPredecessors().size() == 1; + Node pred = p.blockPredecessors().get(0); + int predIndex = p.predecessorsIndex().get(0); + pred.successors().setAndClear(predIndex, p, 0); + p.delete(); + } + } + + // remove FrameStates + for (Node n : graph.getNodes()) { + if (n instanceof FrameState) { + boolean delete = false; + if (n.usages().size() == 0 && n.predecessors().size() == 0) { + delete = true; + } + if (delete) { + n.delete(); + } + } + } + } + + private int nextBlockNumber() { + stats.blockCount++; + return nextBlockNumber++; + } + + private Block nextBlock(int bci) { + Block block = new Block(); + block.startBci = bci; + block.endBci = bci; + block.blockID = nextBlockNumber(); + return block; + } + + private Block unwindBlock() { + if (unwindBlock == null) { + unwindBlock = new Block(); + unwindBlock.startBci = Instruction.SYNCHRONIZATION_ENTRY_BCI; + unwindBlock.endBci = Instruction.SYNCHRONIZATION_ENTRY_BCI; + unwindBlock.blockID = nextBlockNumber(); + addToWorkList(unwindBlock); + } + return unwindBlock; + } + + private Block returnBlock() { + if (returnBlock == null) { + returnBlock = new Block(); + returnBlock.startBci = Instruction.SYNCHRONIZATION_ENTRY_BCI; + returnBlock.endBci = Instruction.SYNCHRONIZATION_ENTRY_BCI; + returnBlock.blockID = nextBlockNumber(); + addToWorkList(returnBlock); + } + return returnBlock; + } + + private void markOnWorkList(Block block) { + blocksOnWorklist.add(block); + } + + private boolean isOnWorkList(Block block) { + return blocksOnWorklist.contains(block); + } + + private void markVisited(Block block) { + blocksVisited.add(block); + } + + private boolean isVisited(Block block) { + return blocksVisited.contains(block); + } + + private void finishStartBlock(Block startBlock) { + assert bci() == 0; + Instruction target = createTargetAt(0, frameState); + appendGoto(target); + } + + public void mergeOrClone(Block target, FrameStateAccess newState) { + Instruction first = target.firstInstruction; + if (target.isLoopHeader && isVisited(target)) { + first = ((LoopBegin) first).loopEnd(); + } + assert first instanceof StateSplit; + + int bci = target.startBci; + + FrameState existingState = ((StateSplit) first).stateBefore(); + + if (existingState == null) { + // copy state because it is modified + FrameState duplicate = newState.duplicate(bci); + + // if the block is a loop header, insert all necessary phis + if (first instanceof LoopBegin && target.isLoopHeader) { + assert first instanceof Merge; + insertLoopPhis((Merge) first, duplicate); + ((Merge) first).setStateBefore(duplicate); + } else { + ((StateSplit) first).setStateBefore(duplicate); + } + } else { + if (!C1XOptions.AssumeVerifiedBytecode && !existingState.isCompatibleWith(newState)) { + // stacks or locks do not match--bytecodes would not verify + TTY.println(existingState.toString()); + TTY.println(newState.duplicate(0).toString()); + throw new CiBailout("stack or locks do not match"); + } + assert existingState.localsSize() == newState.localsSize(); + assert existingState.stackSize() == newState.stackSize(); + + if (first instanceof Placeholder) { + assert !target.isLoopHeader; + Merge merge = new Merge(graph); + + Placeholder p = (Placeholder) first; + assert p.next() == null; + p.replace(merge); + target.firstInstruction = merge; + merge.setStateBefore(existingState); + first = merge; + } + + existingState.merge((Merge) first, newState); + } + + for (int j = 0; j < frameState.localsSize() + frameState.stackSize(); ++j) { + if (frameState.valueAt(j) != null) { + assert !frameState.valueAt(j).isDeleted(); + } + } + } + + private void insertLoopPhis(Merge merge, FrameState newState) { + int stackSize = newState.stackSize(); + for (int i = 0; i < stackSize; i++) { + // always insert phis for the stack + Value x = newState.stackAt(i); + if (x != null) { + newState.setupPhiForStack(merge, i).addInput(x); + } + } + int localsSize = newState.localsSize(); + for (int i = 0; i < localsSize; i++) { + Value x = newState.localAt(i); + if (x != null) { + newState.setupPhiForLocal(merge, i).addInput(x); + } + } + } + + public BytecodeStream stream() { + return stream; + } + + public int bci() { + return stream.currentBCI(); + } + + private void loadLocal(int index, CiKind kind) { + frameState.push(kind, frameState.loadLocal(index)); + } + + private void storeLocal(CiKind kind, int index) { + frameState.storeLocal(index, frameState.pop(kind)); + } + + public boolean covers(RiExceptionHandler handler, int bci) { + return handler.startBCI() <= bci && bci < handler.endBCI(); + } + + public boolean isCatchAll(RiExceptionHandler handler) { + return handler.catchTypeCPI() == 0; + } + + private Instruction handleException(Value exceptionObject, int bci) { + assert bci == Instruction.SYNCHRONIZATION_ENTRY_BCI || bci == bci() : "invalid bci"; + + RiExceptionHandler firstHandler = null; + RiExceptionHandler[] exceptionHandlers = method.exceptionHandlers(); + // join with all potential exception handlers + if (exceptionHandlers != null) { + for (RiExceptionHandler handler : exceptionHandlers) { + // if the handler covers this bytecode index, add it to the list + if (covers(handler, bci)) { + firstHandler = handler; + break; + } + } + } + + if (firstHandler == null) { + firstHandler = syncHandler; + } + + if (firstHandler != null) { + compilation.setHasExceptionHandlers(); + + Block dispatchBlock = null; + for (Block block : blockList) { + if (block instanceof ExceptionBlock) { + ExceptionBlock excBlock = (ExceptionBlock) block; + if (excBlock.handler == firstHandler) { + dispatchBlock = block; + break; + } + } + } + // if there's no dispatch block then the catch block needs to be a catch all + if (dispatchBlock == null) { + assert isCatchAll(firstHandler); + int handlerBCI = firstHandler.handlerBCI(); + if (handlerBCI == Instruction.SYNCHRONIZATION_ENTRY_BCI) { + dispatchBlock = unwindBlock(); + } else { + dispatchBlock = blockFromBci[handlerBCI]; + } + } + FrameState entryState = frameState.duplicateWithEmptyStack(bci); + + StateSplit entry = new Placeholder(graph); + entry.setStateBefore(entryState); + + Instruction currentNext = entry; + Value currentExceptionObject = exceptionObject; + if (currentExceptionObject == null) { + ExceptionObject exception = new ExceptionObject(graph); + entry.setNext(exception); + currentNext = exception; + currentExceptionObject = exception; + } + FrameState stateWithException = entryState.duplicateModified(bci, CiKind.Void, currentExceptionObject); + + Instruction successor = createTarget(dispatchBlock, stateWithException); + currentNext.setNext(successor); + return entry; + } + return null; + } + + private void genLoadConstant(int cpi) { + Object con = constantPool.lookupConstant(cpi); + + if (con instanceof RiType) { + // this is a load of class constant which might be unresolved + RiType riType = (RiType) con; + if (!riType.isResolved()) { + append(new Deoptimize(graph)); + frameState.push(CiKind.Object, append(Constant.forObject(null, graph))); + } else { + frameState.push(CiKind.Object, append(new Constant(riType.getEncoding(Representation.JavaClass), graph))); + } + } else if (con instanceof CiConstant) { + CiConstant constant = (CiConstant) con; + frameState.push(constant.kind.stackKind(), appendConstant(constant)); + } else { + throw new Error("lookupConstant returned an object of incorrect type"); + } + } + + private void genLoadIndexed(CiKind kind) { + Value index = frameState.ipop(); + Value array = frameState.apop(); + Value length = append(new ArrayLength(array, graph)); + Value v = append(new LoadIndexed(array, index, length, kind, graph)); + frameState.push(kind.stackKind(), v); + } + + private void genStoreIndexed(CiKind kind) { + Value value = frameState.pop(kind.stackKind()); + Value index = frameState.ipop(); + Value array = frameState.apop(); + Value length = append(new ArrayLength(array, graph)); + StoreIndexed result = new StoreIndexed(array, index, length, kind, value, graph); + append(result); + } + + private void stackOp(int opcode) { + switch (opcode) { + case POP: { + frameState.xpop(); + break; + } + case POP2: { + frameState.xpop(); + frameState.xpop(); + break; + } + case DUP: { + Value w = frameState.xpop(); + frameState.xpush(w); + frameState.xpush(w); + break; + } + case DUP_X1: { + Value w1 = frameState.xpop(); + Value w2 = frameState.xpop(); + frameState.xpush(w1); + frameState.xpush(w2); + frameState.xpush(w1); + break; + } + case DUP_X2: { + Value w1 = frameState.xpop(); + Value w2 = frameState.xpop(); + Value w3 = frameState.xpop(); + frameState.xpush(w1); + frameState.xpush(w3); + frameState.xpush(w2); + frameState.xpush(w1); + break; + } + case DUP2: { + Value w1 = frameState.xpop(); + Value w2 = frameState.xpop(); + frameState.xpush(w2); + frameState.xpush(w1); + frameState.xpush(w2); + frameState.xpush(w1); + break; + } + case DUP2_X1: { + Value w1 = frameState.xpop(); + Value w2 = frameState.xpop(); + Value w3 = frameState.xpop(); + frameState.xpush(w2); + frameState.xpush(w1); + frameState.xpush(w3); + frameState.xpush(w2); + frameState.xpush(w1); + break; + } + case DUP2_X2: { + Value w1 = frameState.xpop(); + Value w2 = frameState.xpop(); + Value w3 = frameState.xpop(); + Value w4 = frameState.xpop(); + frameState.xpush(w2); + frameState.xpush(w1); + frameState.xpush(w4); + frameState.xpush(w3); + frameState.xpush(w2); + frameState.xpush(w1); + break; + } + case SWAP: { + Value w1 = frameState.xpop(); + Value w2 = frameState.xpop(); + frameState.xpush(w1); + frameState.xpush(w2); + break; + } + default: + throw Util.shouldNotReachHere(); + } + + } + + private void genArithmeticOp(CiKind kind, int opcode) { + genArithmeticOp(kind, opcode, false); + } + + private void genArithmeticOp(CiKind kind, int opcode, boolean canTrap) { + genArithmeticOp(kind, opcode, kind, kind, canTrap); + } + + private void genArithmeticOp(CiKind result, int opcode, CiKind x, CiKind y, boolean canTrap) { + Value yValue = frameState.pop(y); + Value xValue = frameState.pop(x); + Value result1 = append(new Arithmetic(opcode, result, xValue, yValue, isStrict(method.accessFlags()), canTrap, graph)); + if (canTrap) { + append(new ValueAnchor(result1, graph)); + } + frameState.push(result, result1); + } + + private void genNegateOp(CiKind kind) { + frameState.push(kind, append(new Negate(frameState.pop(kind), graph))); + } + + private void genShiftOp(CiKind kind, int opcode) { + Value s = frameState.ipop(); + Value x = frameState.pop(kind); + Shift v; + switch(opcode){ + case ISHL: + case LSHL: v = new LeftShift(kind, x, s, graph); break; + case ISHR: + case LSHR: v = new RightShift(kind, x, s, graph); break; + case IUSHR: + case LUSHR: v = new UnsignedRightShift(kind, x, s, graph); break; + default: + throw new CiBailout("should not reach"); + } + frameState.push(kind, append(v)); + } + + private void genLogicOp(CiKind kind, int opcode) { + Value y = frameState.pop(kind); + Value x = frameState.pop(kind); + Logic v; + switch(opcode){ + case IAND: + case LAND: v = new And(kind, x, y, graph); break; + case IOR: + case LOR: v = new Or(kind, x, y, graph); break; + case IXOR: + case LXOR: v = new Xor(kind, x, y, graph); break; + default: + throw new CiBailout("should not reach"); + } + frameState.push(kind, append(v)); + } + + private void genCompareOp(CiKind kind, int opcode, CiKind resultKind) { + Value y = frameState.pop(kind); + Value x = frameState.pop(kind); + Value value = append(new NormalizeCompare(opcode, resultKind, x, y, graph)); + if (!resultKind.isVoid()) { + frameState.ipush(value); + } + } + + private void genConvert(int opcode, CiKind from, CiKind to) { + CiKind tt = to.stackKind(); + frameState.push(tt, append(new Convert(opcode, frameState.pop(from.stackKind()), tt, graph))); + } + + private void genIncrement() { + int index = stream().readLocalIndex(); + int delta = stream().readIncrement(); + Value x = frameState.localAt(index); + Value y = append(Constant.forInt(delta, graph)); + frameState.storeLocal(index, append(new Arithmetic(IADD, CiKind.Int, x, y, isStrict(method.accessFlags()), false, graph))); + } + + private void genGoto(int fromBCI, int toBCI) { + appendGoto(createTargetAt(toBCI, frameState)); + } + + private void ifNode(Value x, Condition cond, Value y) { + assert !x.isDeleted() && !y.isDeleted(); + If ifNode = new If(new Compare(x, cond, y, graph), graph); + append(ifNode); + Instruction tsucc = createTargetAt(stream().readBranchDest(), frameState); + ifNode.setBlockSuccessor(0, tsucc); + Instruction fsucc = createTargetAt(stream().nextBCI(), frameState); + ifNode.setBlockSuccessor(1, fsucc); + } + + private void genIfZero(Condition cond) { + Value y = appendConstant(CiConstant.INT_0); + Value x = frameState.ipop(); + ifNode(x, cond, y); + } + + private void genIfNull(Condition cond) { + Value y = appendConstant(CiConstant.NULL_OBJECT); + Value x = frameState.apop(); + ifNode(x, cond, y); + } + + private void genIfSame(CiKind kind, Condition cond) { + Value y = frameState.pop(kind); + Value x = frameState.pop(kind); + assert !x.isDeleted() && !y.isDeleted(); + ifNode(x, cond, y); + } + + private void genThrow(int bci) { + Value exception = frameState.apop(); + append(new NullCheck(exception, graph)); + + Instruction entry = handleException(exception, bci); + if (entry != null) { + append(entry); + } else { + frameState.clearStack(); + frameState.apush(exception); + appendGoto(createTarget(unwindBlock(), frameState)); + } + } + + private void genCheckCast() { + int cpi = stream().readCPI(); + RiType type = constantPool.lookupType(cpi, CHECKCAST); + boolean isInitialized = type.isResolved(); + Value typeInstruction = genTypeOrDeopt(RiType.Representation.ObjectHub, type, isInitialized, cpi); + Value object = frameState.apop(); + if (typeInstruction != null) { + frameState.apush(append(new CheckCast(type, typeInstruction, object, graph))); + } else { + frameState.apush(appendConstant(CiConstant.NULL_OBJECT)); + } + } + + private void genInstanceOf() { + int cpi = stream().readCPI(); + RiType type = constantPool.lookupType(cpi, INSTANCEOF); + boolean isInitialized = type.isResolved(); + Value typeInstruction = genTypeOrDeopt(RiType.Representation.ObjectHub, type, isInitialized, cpi); + Value object = frameState.apop(); + if (typeInstruction != null) { + frameState.ipush(append(new InstanceOf(type, typeInstruction, object, graph))); + } else { + frameState.ipush(appendConstant(CiConstant.INT_0)); + } + } + + void genNewInstance(int cpi) { + RiType type = constantPool.lookupType(cpi, NEW); + if (type.isResolved()) { + NewInstance n = new NewInstance(type, cpi, constantPool, graph); + frameState.apush(append(n)); + } else { + append(new Deoptimize(graph)); + frameState.apush(appendConstant(CiConstant.NULL_OBJECT)); + } + } + + private void genNewTypeArray(int typeCode) { + CiKind kind = CiKind.fromArrayTypeCode(typeCode); + RiType elementType = runtime.asRiType(kind); + NewTypeArray nta = new NewTypeArray(frameState.ipop(), elementType, graph); + frameState.apush(append(nta)); + } + + private void genNewObjectArray(int cpi) { + RiType type = constantPool.lookupType(cpi, ANEWARRAY); + Value length = frameState.ipop(); + if (type.isResolved()) { + NewArray n = new NewObjectArray(type, length, graph); + frameState.apush(append(n)); + } else { + append(new Deoptimize(graph)); + frameState.apush(appendConstant(CiConstant.NULL_OBJECT)); + } + + } + + private void genNewMultiArray(int cpi) { + RiType type = constantPool.lookupType(cpi, MULTIANEWARRAY); + int rank = stream().readUByte(bci() + 3); + Value[] dims = new Value[rank]; + for (int i = rank - 1; i >= 0; i--) { + dims[i] = frameState.ipop(); + } + if (type.isResolved()) { + NewArray n = new NewMultiArray(type, dims, cpi, constantPool, graph); + frameState.apush(append(n)); + } else { + append(new Deoptimize(graph)); + frameState.apush(appendConstant(CiConstant.NULL_OBJECT)); + } + } + + private void genGetField(int cpi, RiField field) { + CiKind kind = field.kind(); + Value receiver = frameState.apop(); + if (field.isResolved()) { + LoadField load = new LoadField(receiver, field, graph); + appendOptimizedLoadField(kind, load); + } else { + append(new Deoptimize(graph)); + frameState.push(kind.stackKind(), append(Constant.defaultForKind(kind, graph))); + } + } + + private void genPutField(int cpi, RiField field) { + Value value = frameState.pop(field.kind().stackKind()); + Value receiver = frameState.apop(); + if (field.isResolved()) { + StoreField store = new StoreField(receiver, field, value, graph); + appendOptimizedStoreField(store); + } else { + append(new Deoptimize(graph)); + } + } + + private void genGetStatic(int cpi, RiField field) { + RiType holder = field.holder(); + boolean isInitialized = field.isResolved(); + CiConstant constantValue = null; + if (isInitialized) { + constantValue = field.constantValue(null); + } + if (constantValue != null) { + frameState.push(constantValue.kind.stackKind(), appendConstant(constantValue)); + } else { + Value container = genTypeOrDeopt(RiType.Representation.StaticFields, holder, isInitialized, cpi); + CiKind kind = field.kind(); + if (container != null) { + LoadField load = new LoadField(container, field, graph); + appendOptimizedLoadField(kind, load); + } else { + append(new Deoptimize(graph)); + frameState.push(kind.stackKind(), append(Constant.defaultForKind(kind, graph))); + } + } + } + + private void genPutStatic(int cpi, RiField field) { + RiType holder = field.holder(); + Value container = genTypeOrDeopt(RiType.Representation.StaticFields, holder, field.isResolved(), cpi); + Value value = frameState.pop(field.kind().stackKind()); + if (container != null) { + StoreField store = new StoreField(container, field, value, graph); + appendOptimizedStoreField(store); + } else { + append(new Deoptimize(graph)); + } + } + + private Value genTypeOrDeopt(RiType.Representation representation, RiType holder, boolean initialized, int cpi) { + if (initialized) { + return appendConstant(holder.getEncoding(representation)); + } else { + append(new Deoptimize(graph)); + return null; + } + } + + private void appendOptimizedStoreField(StoreField store) { + append(store); + } + + private void appendOptimizedLoadField(CiKind kind, LoadField load) { + // append the load to the instruction + Value optimized = append(load); + frameState.push(kind.stackKind(), optimized); + } + + private void genInvokeStatic(RiMethod target, int cpi, RiConstantPool constantPool) { + RiType holder = target.holder(); + boolean isInitialized = target.isResolved() && holder.isInitialized(); + if (!isInitialized && C1XOptions.ResolveClassBeforeStaticInvoke) { + // Re-use the same resolution code as for accessing a static field. Even though + // the result of resolution is not used by the invocation (only the side effect + // of initialization is required), it can be commoned with static field accesses. + genTypeOrDeopt(RiType.Representation.StaticFields, holder, isInitialized, cpi); + } + Value[] args = frameState.popArguments(target.signature().argumentSlots(false)); + appendInvoke(INVOKESTATIC, target, args, cpi, constantPool); + } + + private void genInvokeInterface(RiMethod target, int cpi, RiConstantPool constantPool) { + Value[] args = frameState.popArguments(target.signature().argumentSlots(true)); + genInvokeIndirect(INVOKEINTERFACE, target, args, cpi, constantPool); + + } + + private void genInvokeVirtual(RiMethod target, int cpi, RiConstantPool constantPool) { + Value[] args = frameState.popArguments(target.signature().argumentSlots(true)); + genInvokeIndirect(INVOKEVIRTUAL, target, args, cpi, constantPool); + + } + + private void genInvokeSpecial(RiMethod target, RiType knownHolder, int cpi, RiConstantPool constantPool) { + Value[] args = frameState.popArguments(target.signature().argumentSlots(true)); + invokeDirect(target, args, knownHolder, cpi, constantPool); + + } + + private void genInvokeIndirect(int opcode, RiMethod target, Value[] args, int cpi, RiConstantPool constantPool) { + Value receiver = args[0]; + // attempt to devirtualize the call + if (target.isResolved()) { + RiType klass = target.holder(); + + // 0. check for trivial cases + if (target.canBeStaticallyBound() && !isAbstract(target.accessFlags())) { + // check for trivial cases (e.g. final methods, nonvirtual methods) + invokeDirect(target, args, target.holder(), cpi, constantPool); + return; + } + // 1. check if the exact type of the receiver can be determined + RiType exact = getExactType(klass, receiver); + if (exact != null && exact.isResolved()) { + // either the holder class is exact, or the receiver object has an exact type + invokeDirect(exact.resolveMethodImpl(target), args, exact, cpi, constantPool); + return; + } + } + // devirtualization failed, produce an actual invokevirtual + appendInvoke(opcode, target, args, cpi, constantPool); + } + + private CiKind returnKind(RiMethod target) { + return target.signature().returnKind(); + } + + private void invokeDirect(RiMethod target, Value[] args, RiType knownHolder, int cpi, RiConstantPool constantPool) { + appendInvoke(INVOKESPECIAL, target, args, cpi, constantPool); + } + + private void appendInvoke(int opcode, RiMethod target, Value[] args, int cpi, RiConstantPool constantPool) { + CiKind resultType = returnKind(target); + Invoke invoke = new Invoke(bci(), opcode, resultType.stackKind(), args, target, target.signature().returnType(method.holder()), graph); + Value result = appendWithBCI(invoke); + invoke.setExceptionEdge(handleException(null, bci())); + frameState.pushReturn(resultType, result); + } + + private RiType getExactType(RiType staticType, Value receiver) { + RiType exact = staticType.exactType(); + if (exact == null) { + exact = receiver.exactType(); + if (exact == null) { + if (receiver.isConstant()) { + exact = runtime.getTypeOf(receiver.asConstant()); + } + if (exact == null) { + RiType declared = receiver.declaredType(); + exact = declared == null || !declared.isResolved() ? null : declared.exactType(); + } + } + } + return exact; + } + + private void callRegisterFinalizer() { + Value receiver = frameState.loadLocal(0); + RiType declaredType = receiver.declaredType(); + RiType receiverType = declaredType; + RiType exactType = receiver.exactType(); + if (exactType == null && declaredType != null) { + exactType = declaredType.exactType(); + } + if (exactType == null && receiver instanceof Local && ((Local) receiver).index() == 0) { + // the exact type isn't known, but the receiver is parameter 0 => use holder + receiverType = method.holder(); + exactType = receiverType.exactType(); + } + boolean needsCheck = true; + if (exactType != null) { + // we have an exact type + needsCheck = exactType.hasFinalizer(); + } else { + // if either the declared type of receiver or the holder can be assumed to have no finalizers + if (declaredType != null && !declaredType.hasFinalizableSubclass()) { + if (compilation.recordNoFinalizableSubclassAssumption(declaredType)) { + needsCheck = false; + } + } + + if (receiverType != null && !receiverType.hasFinalizableSubclass()) { + if (compilation.recordNoFinalizableSubclassAssumption(receiverType)) { + needsCheck = false; + } + } + } + + if (needsCheck) { + // append a call to the finalizer registration + append(new RegisterFinalizer(frameState.loadLocal(0), frameState.create(bci()), graph)); + C1XMetrics.InlinedFinalizerChecks++; + } + } + + private void genReturn(Value x) { + frameState.clearStack(); + if (x != null) { + frameState.push(x.kind, x); + } + appendGoto(createTarget(returnBlock(), frameState)); + } + + private void genMonitorEnter(Value x, int bci) { + int lockNumber = frameState.locksSize(); + MonitorAddress lockAddress = null; + if (runtime.sizeOfBasicObjectLock() != 0) { + lockAddress = new MonitorAddress(lockNumber, graph); + append(lockAddress); + } + MonitorEnter monitorEnter = new MonitorEnter(x, lockAddress, lockNumber, graph); + appendWithBCI(monitorEnter); + frameState.lock(x); + if (bci == Instruction.SYNCHRONIZATION_ENTRY_BCI) { + monitorEnter.setStateAfter(frameState.create(0)); + } + } + + private void genMonitorExit(Value x) { + int lockNumber = frameState.locksSize() - 1; + if (lockNumber < 0) { + throw new CiBailout("monitor stack underflow"); + } + MonitorAddress lockAddress = null; + if (runtime.sizeOfBasicObjectLock() != 0) { + lockAddress = new MonitorAddress(lockNumber, graph); + append(lockAddress); + } + appendWithBCI(new MonitorExit(x, lockAddress, lockNumber, graph)); + frameState.unlock(); + } + + private void genJsr(int dest) { + throw new CiBailout("jsr/ret not supported"); + } + + private void genRet(int localIndex) { + throw new CiBailout("jsr/ret not supported"); + } + + private void genTableswitch() { + int bci = bci(); + Value value = frameState.ipop(); + BytecodeTableSwitch ts = new BytecodeTableSwitch(stream(), bci); + int max = ts.numberOfCases(); + List list = new ArrayList(max + 1); + List offsetList = new ArrayList(max + 1); + for (int i = 0; i < max; i++) { + // add all successors to the successor list + int offset = ts.offsetAt(i); + list.add(null); + offsetList.add(offset); + } + int offset = ts.defaultOffset(); + list.add(null); + offsetList.add(offset); + TableSwitch tableSwitch = new TableSwitch(value, list, ts.lowKey(), graph); + for (int i = 0; i < offsetList.size(); ++i) { + tableSwitch.setBlockSuccessor(i, createTargetAt(bci + offsetList.get(i), frameState)); + } + append(tableSwitch); + } + + private void genLookupswitch() { + int bci = bci(); + Value value = frameState.ipop(); + BytecodeLookupSwitch ls = new BytecodeLookupSwitch(stream(), bci); + int max = ls.numberOfCases(); + List list = new ArrayList(max + 1); + List offsetList = new ArrayList(max + 1); + int[] keys = new int[max]; + for (int i = 0; i < max; i++) { + // add all successors to the successor list + int offset = ls.offsetAt(i); + list.add(null); + offsetList.add(offset); + keys[i] = ls.keyAt(i); + } + int offset = ls.defaultOffset(); + list.add(null); + offsetList.add(offset); + LookupSwitch lookupSwitch = new LookupSwitch(value, list, keys, graph); + for (int i = 0; i < offsetList.size(); ++i) { + lookupSwitch.setBlockSuccessor(i, createTargetAt(bci + offsetList.get(i), frameState)); + } + append(lookupSwitch); + } + + private Value appendConstant(CiConstant constant) { + return append(new Constant(constant, graph)); + } + + private Value append(Instruction x) { + return appendWithBCI(x); + } + + private Value append(Value v) { + return v; + } + + private Value appendWithBCI(Instruction x) { + assert x.predecessors().size() == 0 : "instruction should not have been appended yet"; + assert lastInstr.next() == null : "cannot append instruction to instruction which isn't end (" + lastInstr + "->" + lastInstr.next() + ")"; + lastInstr.setNext(x); + + lastInstr = x; + if (++stats.nodeCount >= C1XOptions.MaximumInstructionCount) { + // bailout if we've exceeded the maximum inlining size + throw new CiBailout("Method and/or inlining is too large"); + } + + return x; + } + + private Instruction createTargetAt(int bci, FrameStateAccess stateAfter) { + return createTarget(blockFromBci[bci], stateAfter); + } + + private Instruction createTarget(Block block, FrameStateAccess stateAfter) { + assert block != null && stateAfter != null; + assert block.isLoopHeader || block.firstInstruction == null || block.firstInstruction.next() == null : "non-loop block must be iterated after all its predecessors"; + + if (block.isExceptionEntry) { + assert stateAfter.stackSize() == 1; + } + + if (block.firstInstruction == null) { + if (block.isLoopHeader) { +// block.firstInstruction = new Merge(block.startBci, graph); + + LoopBegin loopBegin = new LoopBegin(graph); + LoopEnd loopEnd = new LoopEnd(graph); + loopEnd.setLoopBegin(loopBegin); + block.firstInstruction = loopBegin; + } else { + block.firstInstruction = new Placeholder(graph); + } + } + mergeOrClone(block, stateAfter); + addToWorkList(block); + + if (block.firstInstruction instanceof LoopBegin && isVisited(block)) { + return ((LoopBegin) block.firstInstruction).loopEnd(); + } else { + return block.firstInstruction; + } + } + + private Value synchronizedObject(FrameStateAccess state, RiMethod target) { + if (isStatic(target.accessFlags())) { + Constant classConstant = new Constant(target.holder().getEncoding(Representation.JavaClass), graph); + return append(classConstant); + } else { + return state.localAt(0); + } + } + + private void iterateAllBlocks() { + Block block; + while ((block = removeFromWorkList()) != null) { + + // remove blocks that have no predecessors by the time it their bytecodes are parsed + if (block.firstInstruction == null) { + markVisited(block); + continue; + } + + if (!isVisited(block)) { + markVisited(block); + // now parse the block + frameState.initializeFrom(((StateSplit) block.firstInstruction).stateBefore()); + lastInstr = block.firstInstruction; + assert block.firstInstruction.next() == null : "instructions already appended at block " + block.blockID; + + if (block == returnBlock) { + createReturnBlock(block); + } else if (block == unwindBlock) { + createUnwindBlock(block); + } else if (block instanceof ExceptionBlock) { + createExceptionDispatch((ExceptionBlock) block); + } else { + iterateBytecodesForBlock(block); + } + } + } + for (Block b : blocksVisited) { + if (b.isLoopHeader) { + LoopBegin begin = (LoopBegin) b.firstInstruction; + LoopEnd end = begin.loopEnd(); + +// This can happen with degenerated loops like this one: +// for (;;) { +// try { +// break; +// } catch (UnresolvedException iioe) { +// } +// } + if (end.stateBefore() != null) { + begin.stateBefore().merge(begin, end.stateBefore()); + } else { + end.delete(); + Merge merge = new Merge(graph); + merge.successors().setAndClear(merge.nextIndex(), begin, begin.nextIndex()); + begin.replace(merge); + } + } + } + } + + private void createUnwindBlock(Block block) { + if (Modifier.isSynchronized(method.accessFlags())) { + genMonitorExit(methodSynchronizedObject); + } + append(graph.createUnwind(frameState.apop())); + } + + private void createReturnBlock(Block block) { + if (method.isConstructor() && method.holder().superType() == null) { + callRegisterFinalizer(); + } + CiKind returnKind = method.signature().returnKind().stackKind(); + Value x = returnKind == CiKind.Void ? null : frameState.pop(returnKind); + assert frameState.stackSize() == 0; + + if (Modifier.isSynchronized(method.accessFlags())) { + genMonitorExit(methodSynchronizedObject); + } + append(graph.createReturn(x)); + } + + private void createExceptionDispatch(ExceptionBlock block) { + if (block.handler == null) { + assert frameState.stackSize() == 1 : "only exception object expected on stack, actual size: " + frameState.stackSize(); + createUnwindBlock(block); + } else { + assert frameState.stackSize() == 1; + + Block nextBlock = block.next == null ? unwindBlock() : block.next; + if (block.handler.catchType().isResolved()) { + Instruction catchSuccessor = createTarget(blockFromBci[block.handler.handlerBCI()], frameState); + Instruction nextDispatch = createTarget(nextBlock, frameState); + append(new ExceptionDispatch(frameState.stackAt(0), catchSuccessor, nextDispatch, block.handler.catchType(), graph)); + } else { + Deoptimize deopt = new Deoptimize(graph); + deopt.setMessage("unresolved " + block.handler.catchType().name()); + append(deopt); + Instruction nextDispatch = createTarget(nextBlock, frameState); + appendGoto(nextDispatch); + } + } + } + + private void appendGoto(Instruction target) { + lastInstr.setNext(target); + } + + private void iterateBytecodesForBlock(Block block) { + assert frameState != null; + + stream.setBCI(block.startBci); + + int endBCI = stream.endBCI(); + boolean blockStart = true; + + int bci = block.startBci; + while (bci < endBCI) { + Block nextBlock = blockFromBci[bci]; + if (nextBlock != null && nextBlock != block) { + assert !nextBlock.isExceptionEntry; + // we fell through to the next block, add a goto and break + appendGoto(createTarget(nextBlock, frameState)); + break; + } + // read the opcode + int opcode = stream.currentBC(); + + traceState(); + traceInstruction(bci, opcode, blockStart); + processBytecode(bci, opcode); + + if (Schedule.isBlockEnd(lastInstr) || lastInstr.next() != null) { + break; + } + + stream.next(); + bci = stream.currentBCI(); + if (lastInstr instanceof StateSplit) { + StateSplit stateSplit = (StateSplit) lastInstr; + if (stateSplit.stateAfter() == null && stateSplit.needsStateAfter()) { + stateSplit.setStateAfter(frameState.create(bci)); + } + } + blockStart = false; + } + } + + private void traceState() { + if (C1XOptions.TraceBytecodeParserLevel >= TRACELEVEL_STATE && !TTY.isSuppressed()) { + log.println(String.format("| state [nr locals = %d, stack depth = %d, method = %s]", frameState.localsSize(), frameState.stackSize(), method)); + for (int i = 0; i < frameState.localsSize(); ++i) { + Value value = frameState.localAt(i); + log.println(String.format("| local[%d] = %-8s : %s", i, value == null ? "bogus" : value.kind.javaName, value)); + } + for (int i = 0; i < frameState.stackSize(); ++i) { + Value value = frameState.stackAt(i); + log.println(String.format("| stack[%d] = %-8s : %s", i, value == null ? "bogus" : value.kind.javaName, value)); + } + for (int i = 0; i < frameState.locksSize(); ++i) { + Value value = frameState.lockAt(i); + log.println(String.format("| lock[%d] = %-8s : %s", i, value == null ? "bogus" : value.kind.javaName, value)); + } + } + } + + private void processBytecode(int bci, int opcode) { + int cpi; + + // Checkstyle: stop + switch (opcode) { + case NOP : /* nothing to do */ break; + case ACONST_NULL : frameState.apush(appendConstant(CiConstant.NULL_OBJECT)); break; + case ICONST_M1 : frameState.ipush(appendConstant(CiConstant.INT_MINUS_1)); break; + case ICONST_0 : frameState.ipush(appendConstant(CiConstant.INT_0)); break; + case ICONST_1 : frameState.ipush(appendConstant(CiConstant.INT_1)); break; + case ICONST_2 : frameState.ipush(appendConstant(CiConstant.INT_2)); break; + case ICONST_3 : frameState.ipush(appendConstant(CiConstant.INT_3)); break; + case ICONST_4 : frameState.ipush(appendConstant(CiConstant.INT_4)); break; + case ICONST_5 : frameState.ipush(appendConstant(CiConstant.INT_5)); break; + case LCONST_0 : frameState.lpush(appendConstant(CiConstant.LONG_0)); break; + case LCONST_1 : frameState.lpush(appendConstant(CiConstant.LONG_1)); break; + case FCONST_0 : frameState.fpush(appendConstant(CiConstant.FLOAT_0)); break; + case FCONST_1 : frameState.fpush(appendConstant(CiConstant.FLOAT_1)); break; + case FCONST_2 : frameState.fpush(appendConstant(CiConstant.FLOAT_2)); break; + case DCONST_0 : frameState.dpush(appendConstant(CiConstant.DOUBLE_0)); break; + case DCONST_1 : frameState.dpush(appendConstant(CiConstant.DOUBLE_1)); break; + case BIPUSH : frameState.ipush(appendConstant(CiConstant.forInt(stream.readByte()))); break; + case SIPUSH : frameState.ipush(appendConstant(CiConstant.forInt(stream.readShort()))); break; + case LDC : // fall through + case LDC_W : // fall through + case LDC2_W : genLoadConstant(stream.readCPI()); break; + case ILOAD : loadLocal(stream.readLocalIndex(), CiKind.Int); break; + case LLOAD : loadLocal(stream.readLocalIndex(), CiKind.Long); break; + case FLOAD : loadLocal(stream.readLocalIndex(), CiKind.Float); break; + case DLOAD : loadLocal(stream.readLocalIndex(), CiKind.Double); break; + case ALOAD : loadLocal(stream.readLocalIndex(), CiKind.Object); break; + case ILOAD_0 : // fall through + case ILOAD_1 : // fall through + case ILOAD_2 : // fall through + case ILOAD_3 : loadLocal(opcode - ILOAD_0, CiKind.Int); break; + case LLOAD_0 : // fall through + case LLOAD_1 : // fall through + case LLOAD_2 : // fall through + case LLOAD_3 : loadLocal(opcode - LLOAD_0, CiKind.Long); break; + case FLOAD_0 : // fall through + case FLOAD_1 : // fall through + case FLOAD_2 : // fall through + case FLOAD_3 : loadLocal(opcode - FLOAD_0, CiKind.Float); break; + case DLOAD_0 : // fall through + case DLOAD_1 : // fall through + case DLOAD_2 : // fall through + case DLOAD_3 : loadLocal(opcode - DLOAD_0, CiKind.Double); break; + case ALOAD_0 : // fall through + case ALOAD_1 : // fall through + case ALOAD_2 : // fall through + case ALOAD_3 : loadLocal(opcode - ALOAD_0, CiKind.Object); break; + case IALOAD : genLoadIndexed(CiKind.Int ); break; + case LALOAD : genLoadIndexed(CiKind.Long ); break; + case FALOAD : genLoadIndexed(CiKind.Float ); break; + case DALOAD : genLoadIndexed(CiKind.Double); break; + case AALOAD : genLoadIndexed(CiKind.Object); break; + case BALOAD : genLoadIndexed(CiKind.Byte ); break; + case CALOAD : genLoadIndexed(CiKind.Char ); break; + case SALOAD : genLoadIndexed(CiKind.Short ); break; + case ISTORE : storeLocal(CiKind.Int, stream.readLocalIndex()); break; + case LSTORE : storeLocal(CiKind.Long, stream.readLocalIndex()); break; + case FSTORE : storeLocal(CiKind.Float, stream.readLocalIndex()); break; + case DSTORE : storeLocal(CiKind.Double, stream.readLocalIndex()); break; + case ASTORE : storeLocal(CiKind.Object, stream.readLocalIndex()); break; + case ISTORE_0 : // fall through + case ISTORE_1 : // fall through + case ISTORE_2 : // fall through + case ISTORE_3 : storeLocal(CiKind.Int, opcode - ISTORE_0); break; + case LSTORE_0 : // fall through + case LSTORE_1 : // fall through + case LSTORE_2 : // fall through + case LSTORE_3 : storeLocal(CiKind.Long, opcode - LSTORE_0); break; + case FSTORE_0 : // fall through + case FSTORE_1 : // fall through + case FSTORE_2 : // fall through + case FSTORE_3 : storeLocal(CiKind.Float, opcode - FSTORE_0); break; + case DSTORE_0 : // fall through + case DSTORE_1 : // fall through + case DSTORE_2 : // fall through + case DSTORE_3 : storeLocal(CiKind.Double, opcode - DSTORE_0); break; + case ASTORE_0 : // fall through + case ASTORE_1 : // fall through + case ASTORE_2 : // fall through + case ASTORE_3 : storeLocal(CiKind.Object, opcode - ASTORE_0); break; + case IASTORE : genStoreIndexed(CiKind.Int ); break; + case LASTORE : genStoreIndexed(CiKind.Long ); break; + case FASTORE : genStoreIndexed(CiKind.Float ); break; + case DASTORE : genStoreIndexed(CiKind.Double); break; + case AASTORE : genStoreIndexed(CiKind.Object); break; + case BASTORE : genStoreIndexed(CiKind.Byte ); break; + case CASTORE : genStoreIndexed(CiKind.Char ); break; + case SASTORE : genStoreIndexed(CiKind.Short ); break; + case POP : // fall through + case POP2 : // fall through + case DUP : // fall through + case DUP_X1 : // fall through + case DUP_X2 : // fall through + case DUP2 : // fall through + case DUP2_X1 : // fall through + case DUP2_X2 : // fall through + case SWAP : stackOp(opcode); break; + case IADD : // fall through + case ISUB : // fall through + case IMUL : genArithmeticOp(CiKind.Int, opcode); break; + case IDIV : // fall through + case IREM : genArithmeticOp(CiKind.Int, opcode, true); break; + case LADD : // fall through + case LSUB : // fall through + case LMUL : genArithmeticOp(CiKind.Long, opcode); break; + case LDIV : // fall through + case LREM : genArithmeticOp(CiKind.Long, opcode, true); break; + case FADD : // fall through + case FSUB : // fall through + case FMUL : // fall through + case FDIV : // fall through + case FREM : genArithmeticOp(CiKind.Float, opcode); break; + case DADD : // fall through + case DSUB : // fall through + case DMUL : // fall through + case DDIV : // fall through + case DREM : genArithmeticOp(CiKind.Double, opcode); break; + case INEG : genNegateOp(CiKind.Int); break; + case LNEG : genNegateOp(CiKind.Long); break; + case FNEG : genNegateOp(CiKind.Float); break; + case DNEG : genNegateOp(CiKind.Double); break; + case ISHL : // fall through + case ISHR : // fall through + case IUSHR : genShiftOp(CiKind.Int, opcode); break; + case IAND : // fall through + case IOR : // fall through + case IXOR : genLogicOp(CiKind.Int, opcode); break; + case LSHL : // fall through + case LSHR : // fall through + case LUSHR : genShiftOp(CiKind.Long, opcode); break; + case LAND : // fall through + case LOR : // fall through + case LXOR : genLogicOp(CiKind.Long, opcode); break; + case IINC : genIncrement(); break; + case I2L : genConvert(opcode, CiKind.Int , CiKind.Long ); break; + case I2F : genConvert(opcode, CiKind.Int , CiKind.Float ); break; + case I2D : genConvert(opcode, CiKind.Int , CiKind.Double); break; + case L2I : genConvert(opcode, CiKind.Long , CiKind.Int ); break; + case L2F : genConvert(opcode, CiKind.Long , CiKind.Float ); break; + case L2D : genConvert(opcode, CiKind.Long , CiKind.Double); break; + case F2I : genConvert(opcode, CiKind.Float , CiKind.Int ); break; + case F2L : genConvert(opcode, CiKind.Float , CiKind.Long ); break; + case F2D : genConvert(opcode, CiKind.Float , CiKind.Double); break; + case D2I : genConvert(opcode, CiKind.Double, CiKind.Int ); break; + case D2L : genConvert(opcode, CiKind.Double, CiKind.Long ); break; + case D2F : genConvert(opcode, CiKind.Double, CiKind.Float ); break; + case I2B : genConvert(opcode, CiKind.Int , CiKind.Byte ); break; + case I2C : genConvert(opcode, CiKind.Int , CiKind.Char ); break; + case I2S : genConvert(opcode, CiKind.Int , CiKind.Short ); break; + case LCMP : genCompareOp(CiKind.Long, opcode, CiKind.Int); break; + case FCMPL : genCompareOp(CiKind.Float, opcode, CiKind.Int); break; + case FCMPG : genCompareOp(CiKind.Float, opcode, CiKind.Int); break; + case DCMPL : genCompareOp(CiKind.Double, opcode, CiKind.Int); break; + case DCMPG : genCompareOp(CiKind.Double, opcode, CiKind.Int); break; + case IFEQ : genIfZero(Condition.EQ); break; + case IFNE : genIfZero(Condition.NE); break; + case IFLT : genIfZero(Condition.LT); break; + case IFGE : genIfZero(Condition.GE); break; + case IFGT : genIfZero(Condition.GT); break; + case IFLE : genIfZero(Condition.LE); break; + case IF_ICMPEQ : genIfSame(CiKind.Int, Condition.EQ); break; + case IF_ICMPNE : genIfSame(CiKind.Int, Condition.NE); break; + case IF_ICMPLT : genIfSame(CiKind.Int, Condition.LT); break; + case IF_ICMPGE : genIfSame(CiKind.Int, Condition.GE); break; + case IF_ICMPGT : genIfSame(CiKind.Int, Condition.GT); break; + case IF_ICMPLE : genIfSame(CiKind.Int, Condition.LE); break; + case IF_ACMPEQ : genIfSame(frameState.peekKind(), Condition.EQ); break; + case IF_ACMPNE : genIfSame(frameState.peekKind(), Condition.NE); break; + case GOTO : genGoto(stream.currentBCI(), stream.readBranchDest()); break; + case JSR : genJsr(stream.readBranchDest()); break; + case RET : genRet(stream.readLocalIndex()); break; + case TABLESWITCH : genTableswitch(); break; + case LOOKUPSWITCH : genLookupswitch(); break; + case IRETURN : genReturn(frameState.ipop()); break; + case LRETURN : genReturn(frameState.lpop()); break; + case FRETURN : genReturn(frameState.fpop()); break; + case DRETURN : genReturn(frameState.dpop()); break; + case ARETURN : genReturn(frameState.apop()); break; + case RETURN : genReturn(null ); break; + case GETSTATIC : cpi = stream.readCPI(); genGetStatic(cpi, constantPool.lookupField(cpi, opcode)); break; + case PUTSTATIC : cpi = stream.readCPI(); genPutStatic(cpi, constantPool.lookupField(cpi, opcode)); break; + case GETFIELD : cpi = stream.readCPI(); genGetField(cpi, constantPool.lookupField(cpi, opcode)); break; + case PUTFIELD : cpi = stream.readCPI(); genPutField(cpi, constantPool.lookupField(cpi, opcode)); break; + case INVOKEVIRTUAL : cpi = stream.readCPI(); genInvokeVirtual(constantPool.lookupMethod(cpi, opcode), cpi, constantPool); break; + case INVOKESPECIAL : cpi = stream.readCPI(); genInvokeSpecial(constantPool.lookupMethod(cpi, opcode), null, cpi, constantPool); break; + case INVOKESTATIC : cpi = stream.readCPI(); genInvokeStatic(constantPool.lookupMethod(cpi, opcode), cpi, constantPool); break; + case INVOKEINTERFACE: cpi = stream.readCPI(); genInvokeInterface(constantPool.lookupMethod(cpi, opcode), cpi, constantPool); break; + case NEW : genNewInstance(stream.readCPI()); break; + case NEWARRAY : genNewTypeArray(stream.readLocalIndex()); break; + case ANEWARRAY : genNewObjectArray(stream.readCPI()); break; + case ARRAYLENGTH : genArrayLength(); break; + case ATHROW : genThrow(stream.currentBCI()); break; + case CHECKCAST : genCheckCast(); break; + case INSTANCEOF : genInstanceOf(); break; + case MONITORENTER : genMonitorEnter(frameState.apop(), stream.currentBCI()); break; + case MONITOREXIT : genMonitorExit(frameState.apop()); break; + case MULTIANEWARRAY : genNewMultiArray(stream.readCPI()); break; + case IFNULL : genIfNull(Condition.EQ); break; + case IFNONNULL : genIfNull(Condition.NE); break; + case GOTO_W : genGoto(stream.currentBCI(), stream.readFarBranchDest()); break; + case JSR_W : genJsr(stream.readFarBranchDest()); break; + case BREAKPOINT: + throw new CiBailout("concurrent setting of breakpoint"); + default: + throw new CiBailout("Unsupported opcode " + opcode + " (" + nameOf(opcode) + ") [bci=" + bci + "]"); + } + // Checkstyle: resume + } + + private void traceInstruction(int bci, int opcode, boolean blockStart) { + if (C1XOptions.TraceBytecodeParserLevel >= TRACELEVEL_INSTRUCTIONS && !TTY.isSuppressed()) { + StringBuilder sb = new StringBuilder(40); + sb.append(blockStart ? '+' : '|'); + if (bci < 10) { + sb.append(" "); + } else if (bci < 100) { + sb.append(' '); + } + sb.append(bci).append(": ").append(Bytecodes.nameOf(opcode)); + for (int i = bci + 1; i < stream.nextBCI(); ++i) { + sb.append(' ').append(stream.readUByte(i)); + } + log.println(sb.toString()); + } + } + + private void genArrayLength() { + frameState.ipush(append(new ArrayLength(frameState.apop(), graph))); + } + + /** + * Adds a block to the worklist, if it is not already in the worklist. + * This method will keep the worklist topologically stored (i.e. the lower + * DFNs are earlier in the list). + * @param block the block to add to the work list + */ + private void addToWorkList(Block block) { + if (!isOnWorkList(block)) { + markOnWorkList(block); + sortIntoWorkList(block); + } + } + + private void sortIntoWorkList(Block top) { + workList.offer(top); + } + + /** + * Removes the next block from the worklist. The list is sorted topologically, so the + * block with the lowest depth first number in the list will be removed and returned. + * @return the next block from the worklist; {@code null} if there are no blocks + * in the worklist + */ + private Block removeFromWorkList() { + return workList.poll(); + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/graph/IR.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/graph/IR.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,251 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.graph; + +import java.util.*; + +import com.oracle.max.graal.compiler.*; +import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.compiler.ir.*; +import com.oracle.max.graal.compiler.lir.*; +import com.oracle.max.graal.compiler.observer.*; +import com.oracle.max.graal.compiler.opt.*; +import com.oracle.max.graal.compiler.schedule.*; +import com.oracle.max.graal.compiler.value.*; +import com.oracle.max.graal.graph.*; + +/** + * This class implements the overall container for the HIR (high-level IR) graph + * and directs its construction, optimization, and finalization. + */ +public class IR { + + /** + * The compilation associated with this IR. + */ + public final C1XCompilation compilation; + + /** + * The start block of this IR. + */ + public LIRBlock startBlock; + + /** + * The linear-scan ordered list of blocks. + */ + private List orderedBlocks; + + /** + * Creates a new IR instance for the specified compilation. + * @param compilation the compilation + */ + public IR(C1XCompilation compilation) { + this.compilation = compilation; + } + + public Map valueToBlock; + + /** + * Builds the graph, optimizes it, and computes the linear scan block order. + */ + public void build() { + if (C1XOptions.PrintTimers) { + C1XTimers.HIR_CREATE.start(); + } + + buildGraph(); + + if (C1XOptions.PrintTimers) { + C1XTimers.HIR_CREATE.stop(); + C1XTimers.HIR_OPTIMIZE.start(); + } + + Graph graph = compilation.graph; + + if (C1XOptions.OptCanonicalizer) { + new CanonicalizerPhase().apply(graph); + verifyAndPrint("After canonicalization"); + } + + // Split critical edges. + List nodes = graph.getNodes(); + for (int i = 0; i < nodes.size(); ++i) { + Node n = nodes.get(i); + if (Schedule.trueSuccessorCount(n) > 1) { + for (int j = 0; j < n.successors().size(); ++j) { + Node succ = n.successors().get(j); + if (Schedule.truePredecessorCount(succ) > 1) { + Anchor a = new Anchor(graph); + a.successors().setAndClear(1, n, j); + n.successors().set(j, a); + } + } + } + } + + Schedule schedule = new Schedule(graph); + List blocks = schedule.getBlocks(); + List lirBlocks = new ArrayList(); + Map map = new HashMap(); + for (Block b : blocks) { + LIRBlock block = new LIRBlock(b.blockID()); + map.put(b, block); + block.setInstructions(b.getInstructions()); + block.setLinearScanNumber(b.blockID()); + + block.setFirstInstruction(b.firstNode()); + block.setLastInstruction(b.lastNode()); + lirBlocks.add(block); + } + + for (Block b : blocks) { + for (Block succ : b.getSuccessors()) { + map.get(b).blockSuccessors().add(map.get(succ)); + } + + for (Block pred : b.getPredecessors()) { + map.get(b).blockPredecessors().add(map.get(pred)); + } + } + + orderedBlocks = lirBlocks; + valueToBlock = new HashMap(); + for (LIRBlock b : orderedBlocks) { + for (Node i : b.getInstructions()) { + valueToBlock.put(i, b); + } + } + startBlock = lirBlocks.get(0); + assert startBlock != null; + assert startBlock.blockPredecessors().size() == 0; + + ComputeLinearScanOrder clso = new ComputeLinearScanOrder(lirBlocks.size(), startBlock); + orderedBlocks = clso.linearScanOrder(); + this.compilation.stats.loopCount = clso.numLoops(); + + int z = 0; + for (LIRBlock b : orderedBlocks) { + b.setLinearScanNumber(z++); + } + + verifyAndPrint("After linear scan order"); + + if (C1XOptions.PrintTimers) { + C1XTimers.HIR_OPTIMIZE.stop(); + } + } + + private void buildGraph() { + // Graph builder must set the startBlock and the osrEntryBlock + new GraphBuilder(compilation, compilation.method, compilation.graph).build(false); + +// CompilerGraph duplicate = new CompilerGraph(); +// Map replacements = new HashMap(); +// replacements.put(compilation.graph.start(), duplicate.start()); +// duplicate.addDuplicate(compilation.graph.getNodes(), replacements); +// compilation.graph = duplicate; + + verifyAndPrint("After graph building"); + + DeadCodeElimination dce = new DeadCodeElimination(); + dce.apply(compilation.graph); + if (dce.deletedNodeCount > 0) { + verifyAndPrint("After dead code elimination"); + } + + if (C1XOptions.Inline) { + new Inlining(compilation, this).apply(compilation.graph); + } + + if (C1XOptions.PrintCompilation) { + TTY.print(String.format("%3d blocks | ", compilation.stats.blockCount)); + } + } + + /** + * Gets the linear scan ordering of blocks as a list. + * @return the blocks in linear scan order + */ + public List linearScanOrder() { + return orderedBlocks; + } + + private void print(boolean cfgOnly) { + if (!TTY.isSuppressed()) { + TTY.println("IR for " + compilation.method); + final InstructionPrinter ip = new InstructionPrinter(TTY.out()); + final BlockPrinter bp = new BlockPrinter(this, ip, cfgOnly); + //getHIRStartBlock().iteratePreOrder(bp); + } + } + + /** + * Verifies the IR and prints it out if the relevant options are set. + * @param phase the name of the phase for printing + */ + public void verifyAndPrint(String phase) { + if (C1XOptions.PrintHIR && !TTY.isSuppressed()) { + TTY.println(phase); + print(false); + } + + if (compilation.compiler.isObserved()) { + compilation.compiler.fireCompilationEvent(new CompilationEvent(compilation, phase, compilation.graph, true, false)); + } + } + + public void printGraph(String phase, Graph graph) { + if (C1XOptions.PrintHIR && !TTY.isSuppressed()) { + TTY.println(phase); + print(false); + } + + if (compilation.compiler.isObserved()) { + compilation.compiler.fireCompilationEvent(new CompilationEvent(compilation, phase, graph, true, false)); + } + } + + public int numLoops() { + return compilation.stats.loopCount; + } + + /** + * Gets the maximum number of locks in the graph's frame states. + */ + public final int maxLocks() { + int maxLocks = 0; + for (Node node : compilation.graph.getNodes()) { + if (node instanceof FrameState) { + int lockCount = ((FrameState) node).locksSize(); + if (lockCount > maxLocks) { + maxLocks = lockCount; + } + } + } + return maxLocks; + } + + public Instruction getHIRStartBlock() { + return (Instruction) compilation.graph.start().successors().get(0); + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/graph/Inlining.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/graph/Inlining.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,288 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.graph; + +import java.lang.reflect.*; +import java.util.*; + +import com.oracle.max.graal.compiler.*; +import com.oracle.max.graal.compiler.ir.*; +import com.oracle.max.graal.compiler.value.*; +import com.oracle.max.graal.graph.*; +import com.sun.cri.ci.*; +import com.sun.cri.ri.*; + + +public class Inlining extends Phase { + + private final C1XCompilation compilation; + private final IR ir; + + private final Queue invokes = new ArrayDeque(); + private final Queue methods = new ArrayDeque(); + private int inliningSize; + + public Inlining(C1XCompilation compilation, IR ir) { + this.compilation = compilation; + this.ir = ir; + } + + private void addToQueue(Invoke invoke, RiMethod method) { + invokes.add(invoke); + methods.add(method); + inliningSize += method.code().length; + } + + @Override + protected void run(Graph graph) { + if (!C1XOptions.Inline) { + return; + } + + inliningSize = compilation.method.code().length; + int iterations = C1XOptions.MaximumRecursiveInlineLevel; + do { + for (Node node : graph.getNodes()) { + if (node instanceof Invoke) { + Invoke invoke = (Invoke) node; + RiMethod target = invoke.target; + if (!checkInliningConditions(invoke) || !target.isResolved() || Modifier.isNative(target.accessFlags())) { + continue; + } + if (target.canBeStaticallyBound()) { + if (checkInliningConditions(invoke.target)) { + addToQueue(invoke, invoke.target); + } + } else { + RiMethod concrete = invoke.target.holder().uniqueConcreteMethod(invoke.target); + if (concrete != null && concrete.isResolved() && !Modifier.isNative(concrete.accessFlags())) { + if (checkInliningConditions(concrete)) { + if (C1XOptions.TraceInlining) { + System.out.println("registering concrete method assumption..."); + } + compilation.assumptions.recordConcreteMethod(invoke.target, concrete); + addToQueue(invoke, concrete); + } + } + } + if (inliningSize > C1XOptions.MaximumInstructionCount) { + break; + } + } + } + + assert invokes.size() == methods.size(); + if (invokes.isEmpty()) { + break; + } + + Invoke invoke; + while ((invoke = invokes.poll()) != null) { + RiMethod method = methods.remove(); + inlineMethod(invoke, method); + } + DeadCodeElimination dce = new DeadCodeElimination(); + dce.apply(graph); + if (dce.deletedNodeCount > 0) { + ir.verifyAndPrint("After dead code elimination"); + } + ir.verifyAndPrint("After inlining iteration"); + + if (inliningSize > C1XOptions.MaximumInstructionCount) { + if (C1XOptions.TraceInlining) { + System.out.println("inlining stopped: MaximumInstructionCount reached"); + } + break; + } + } while(--iterations > 0); + } + + private boolean checkInliningConditions(Invoke invoke) { + String name = invoke.id() + ": " + CiUtil.format("%H.%n(%p):%r", invoke.target, false); + if (invoke.predecessors().size() == 0) { + if (C1XOptions.TraceInlining) { + System.out.println("not inlining " + name + " because the invoke is dead code"); + } + return false; + } + return true; + } + + private boolean checkInliningConditions(RiMethod method) { + String name = null; + if (C1XOptions.TraceInlining) { + name = CiUtil.format("%H.%n(%p):%r", method, false) + " (" + method.code().length + " bytes)"; + } + if (method.code().length > C1XOptions.MaximumInlineSize) { + if (C1XOptions.TraceInlining) { + System.out.println("not inlining " + name + " because of code size"); + } + return false; + } + if (!method.holder().isInitialized()) { + if (C1XOptions.TraceInlining) { + System.out.println("not inlining " + name + " because of non-initialized class"); + } + return false; + } + return true; + } + + private void inlineMethod(Invoke invoke, RiMethod method) { + String name = invoke.id() + ": " + CiUtil.format("%H.%n(%p):%r", method, false) + " (" + method.code().length + " bytes)"; + FrameState stateAfter = invoke.stateAfter(); + Instruction exceptionEdge = invoke.exceptionEdge(); + + if (C1XOptions.TraceInlining) { + System.out.printf("Building graph for %s, locals: %d, stack: %d\n", name, method.maxLocals(), method.maxStackSize()); + } + + CompilerGraph graph = new CompilerGraph(); + new GraphBuilder(compilation, method, graph).build(true); + + boolean withReceiver = !Modifier.isStatic(method.accessFlags()); + + int argumentCount = method.signature().argumentCount(false); + Value[] parameters = new Value[argumentCount + (withReceiver ? 1 : 0)]; + int slot = withReceiver ? 1 : 0; + int param = withReceiver ? 1 : 0; + for (int i = 0; i < argumentCount; i++) { + parameters[param++] = invoke.argument(slot); + slot += method.signature().argumentKindAt(i).sizeInSlots(); + } + if (withReceiver) { + parameters[0] = invoke.argument(0); + } + + HashMap replacements = new HashMap(); + ArrayList nodes = new ArrayList(); + ArrayList frameStates = new ArrayList(); + Return returnNode = null; + Unwind unwindNode = null; + StartNode startNode = graph.start(); + for (Node node : graph.getNodes()) { + if (node != null) { + if (node instanceof StartNode) { + assert startNode == node; + } else if (node instanceof Local) { + replacements.put(node, parameters[((Local) node).index()]); + } else { + nodes.add(node); + if (node instanceof Return) { + returnNode = (Return) node; + } else if (node instanceof Unwind) { + unwindNode = (Unwind) node; + } else if (node instanceof FrameState) { + frameStates.add(node); + } + } + } + } + + if (C1XOptions.TraceInlining) { + ir.printGraph("Subgraph " + CiUtil.format("%H.%n(%p):%r", method, false), graph); + System.out.println("inlining " + name + ": " + frameStates.size() + " frame states, " + nodes.size() + " nodes"); + } + + assert invoke.predecessors().size() == 1 : "size: " + invoke.predecessors().size(); + Instruction pred; + if (withReceiver) { + pred = new NullCheck(parameters[0], compilation.graph); + } else { + pred = new Merge(compilation.graph); + } + invoke.predecessors().get(0).successors().replace(invoke, pred); + replacements.put(startNode, pred); + + Map duplicates = compilation.graph.addDuplicate(nodes, replacements); + + if (returnNode != null) { + List usages = new ArrayList(invoke.usages()); + for (Node usage : usages) { + if (returnNode.result() instanceof Local) { + usage.inputs().replace(invoke, replacements.get(returnNode.result())); + } else { + usage.inputs().replace(invoke, duplicates.get(returnNode.result())); + } + } + Node returnDuplicate = duplicates.get(returnNode); + returnDuplicate.inputs().clearAll(); + + assert returnDuplicate.predecessors().size() == 1; + Node returnPred = returnDuplicate.predecessors().get(0); + int index = returnDuplicate.predecessorsIndex().get(0); + returnPred.successors().setAndClear(index, invoke, 0); + returnDuplicate.delete(); + } + +// if (invoke.next() instanceof Merge) { +// ((Merge) invoke.next()).removePhiPredecessor(invoke); +// } +// invoke.successors().clearAll(); + invoke.inputs().clearAll(); + invoke.setExceptionEdge(null); +// invoke.delete(); + + + if (exceptionEdge != null) { + if (unwindNode != null) { + assert unwindNode.predecessors().size() == 1; + assert exceptionEdge.successors().size() == 1; + ExceptionObject obj = (ExceptionObject) exceptionEdge; + + List usages = new ArrayList(obj.usages()); + for (Node usage : usages) { + if (replacements.containsKey(unwindNode.exception())) { + usage.inputs().replace(obj, replacements.get(unwindNode.exception())); + } else { + usage.inputs().replace(obj, duplicates.get(unwindNode.exception())); + } + } + Node unwindDuplicate = duplicates.get(unwindNode); + unwindDuplicate.inputs().clearAll(); + + assert unwindDuplicate.predecessors().size() == 1; + Node unwindPred = unwindDuplicate.predecessors().get(0); + int index = unwindDuplicate.predecessorsIndex().get(0); + unwindPred.successors().setAndClear(index, obj, 0); + + obj.inputs().clearAll(); + obj.delete(); + unwindDuplicate.delete(); + + } + } + + // adjust all frame states that were copied + if (frameStates.size() > 0) { + FrameState outerFrameState = stateAfter.duplicateModified(invoke.bci, invoke.kind); + for (Node frameState : frameStates) { + ((FrameState) duplicates.get(frameState)).setOuterFrameState(outerFrameState); + } + } + + if (C1XOptions.TraceInlining) { + ir.verifyAndPrint("After inlining " + CiUtil.format("%H.%n(%p):%r", method, false)); + } + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/graph/JSRNotSupportedBailout.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/graph/JSRNotSupportedBailout.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.graph; + +import com.sun.cri.ci.*; + + +public class JSRNotSupportedBailout extends CiBailout{ + private static final long serialVersionUID = -7476925652727154272L; + + public JSRNotSupportedBailout() { + super("jsr/ret not supported"); + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/graph/MemoryMap.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/graph/MemoryMap.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.graph; + +import static java.lang.reflect.Modifier.*; + +import java.util.*; + +import com.oracle.max.graal.compiler.ir.*; +import com.sun.cri.ri.*; + +/** + * The {@code MemoryMap} class is an approximation of memory that is used redundant load and + * store elimination. In C1, tracking of fields of new objects' fields was precise, + * while tracking of other fields is managed at the offset granularity (i.e. a write of a field with offset + * {@code off} will "overwrite" all fields with the offset {@code off}. However, C1X distinguishes all + * loaded fields as separate locations. Static fields have just one location, while instance fields are + * tracked for at most one instance object. Loads or stores of unloaded fields kill all memory locations. + * An object is no longer "new" if it is stored into a field or array. + * + * @author Ben L. Titzer + */ +public class MemoryMap { + + private final HashMap objectMap = new HashMap(); + private final HashMap valueMap = new HashMap(); + private final IdentityHashMap newObjects = new IdentityHashMap(); + + /** + * Kills all memory locations. + */ + public void kill() { + objectMap.clear(); + valueMap.clear(); + newObjects.clear(); + } + + /** + * The specified instruction has just escaped, it can no longer be considered a "new object". + * @param x the instruction that just escaped + */ + public void storeValue(Value x) { + newObjects.remove(x); + } + + /** + * Record a newly allocated object. + * @param n the instruction generating the new object + */ + public void newInstance(NewInstance n) { + newObjects.put(n, n); + } + + /** + * Look up a load for load elimination, and put this load into the load elimination map. + * @param load the instruction representing the load + * @return a reference to the previous instruction that already loaded the value, if it is available; the + * {@code load} parameter otherwise + */ + public Value load(LoadField load) { + if (!load.isLoaded()) { + // the field is not loaded, kill everything, because it will need to be resolved + kill(); + return load; + } + RiField field = load.field(); + if (load.isStatic()) { + // the field is static, look in the static map + Value r = valueMap.get(field); + if (r != null) { + return r; + } + valueMap.put(field, load); + } else { + // see if the value for this object for this field is in the map + if (objectMap.get(field) == load.object()) { + return valueMap.get(field); + } + objectMap.put(field, load.object()); + valueMap.put(field, load); + } + + return load; // load cannot be eliminated + } + + /** + * Insert a new result for a load into the memory map. + * @param load the load instruction + * @param result the result that the load instruction should produce + */ + public void setResult(LoadField load, Value result) { + if (load.isLoaded()) { + RiField field = load.field(); + if (load.isStatic()) { + // the field is static, put it in the static map + valueMap.put(field, result); + } else { + // put the result for the loaded object into the map + objectMap.put(field, load.object()); + valueMap.put(field, result); + } + } + } + + /** + * Look up a store for store elimination, and put this store into the load elimination map. + * @param store the store instruction to put into the map + * @return {@code null} if the store operation is redundant; the {@code store} parameter + * otherwise + */ + public StoreField store(StoreField store) { + if (!store.isLoaded()) { + // the field is not loaded, kill everything, because it will need to be resolved + kill(); + return store; + } + RiField field = store.field(); + Value value = store.value(); + if (store.isStatic()) { + // the field is static, overwrite it into the static map + valueMap.put(field, value); + } else { + if (newObjects.containsKey(store.object())) { + // this is a store to a new object's field + if (fieldHasNoStores(field) && value.isConstant() && value.asConstant().isDefaultValue()) { + // this is a redundant initialization of a new object's field that has not been assigned to + return null; + } + } + Value obj = objectMap.get(field); + if (obj == store.object()) { + // is this a redundant store? + if (value == valueMap.get(field) && !isVolatile(field.accessFlags())) { + return null; + } + } + objectMap.put(field, store.object()); + valueMap.put(field, value); + } + storeValue(value); // the value stored just escaped + return store; // the store cannot be eliminated + } + + private boolean fieldHasNoStores(RiField field) { + return objectMap.get(field) == null; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/graph/package-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/graph/package-info.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + *

IR Graph building

+ * + * The {@link com.oracle.max.graal.compiler.graph.IR} class drives the generation of the HIR graph for a method, making use of other + * utility classes in this package. + * + * The graph building is separated into a basic build phase ({@link com.oracle.max.graal.compiler.graph.IR#buildGraph} method)and + * (currently) two optimization phases ({@link com.oracle.max.graal.compiler.graph.IR#optimize1} and + * {@link com.oracle.max.graal.compiler.graph.IR#optimize2}) although the basic phase also does some (basic) optimizations. + * + *

Basic Graph Build Phase

+ * + * {@code IR.buildGraph} creates an {@link com.oracle.max.graal.compiler.ir.IRScope topScope} object, + * that represents a context for inlining, and then invokes the constructor for the + * {@link com.oracle.max.graal.compiler.graph.GraphBuilder} class, passing the {@link com.oracle.max.graal.compiler.C1XCompilation}, and {@code IR} + * instances, which are cached. The following support objects are created in the constructor: + * + *
    + *
  • {@code memoryMap}: an instance of {@link com.oracle.max.graal.compiler.graph.MemoryMap} + *
  • {@code localValueMap}: an instance of {@link com.oracle.max.graal.compiler.opt.ValueMap} + *
  • {@code canonicalizer}: an instance of {@link com.oracle.max.graal.compiler.opt.Canonicalizer} + *
+ * + * Now the {@link com.oracle.max.graal.compiler.graph.GraphBuilder#build} is invoked with {@code topScope} as argument. + * + *

{@code GraphBuilder.build}

+ * + *
    + *
  1. The {@link com.oracle.max.graal.compiler.graph.IR#startBlock} field of the cached {@link com.oracle.max.graal.compiler.graph.IR} instance is set to a newly created + * {@link com.oracle.max.graal.compiler.ir.BlockBegin} node, with bytecode index 0 and then the {@link com.oracle.max.graal.compiler.graph.BlockMap} is + * constructed by calling {@link com.oracle.max.graal.compiler.C1XCompilation#getBlockMap}. This behaves slightly differently depending on + * whether this is an OSR compilation. If so, a new {@link com.oracle.max.graal.compiler.ir.BlockBegin} node is added to the map at the OSR bytecode + * index. The map is then built by the{@link com.oracle.max.graal.compiler.graph.BlockMap#build}, which takes a boolean argument that + * controls whether a second pass is made over the bytecodes to compute stores in loops. This always false for an OSR + * compilation (why?). Otherwise, it is only true if enabled by the {@link com.oracle.max.graal.compiler.C1XOptions#PhiLoopStores} + * compilation option. FInally some unneeded state from the map is removed by the {@link com.oracle.max.graal.compiler.graph.BlockMap#cleanup} method, and + * the statistics are updated. + *
  2. + * + *
  3. Next the {@link com.oracle.max.graal.compiler.graph.GraphBuilder#pushRootScope} method is called, with the passed-in {@link com.oracle.max.graal.compiler.ir.IRScope} + * object, the {@link com.oracle.max.graal.compiler.graph.BlockMap} returned by build and the {@code startBlock}. (Note: Unlike + * {@link com.oracle.max.graal.compiler.graph.GraphBuilder#pushScope}, this method does not propagate the + * {@link com.oracle.max.graal.compiler.graph.BlockMap#storesInLoops} field to the {@link com.oracle.max.graal.compiler.ir.IRScope} object, which means that + * {@link com.oracle.max.graal.compiler.ir.BlockBegin#insertLoopPhis} will always get null for this value. Is this a bug?). + * {@link com.oracle.max.graal.compiler.graph.GraphBuilder#pushRootScope} initializes the {@link com.oracle.max.graal.compiler.graph.GraphBuilder#scopeData} field with a + * {@link com.oracle.max.graal.compiler.graph.ScopeData} instance, with null parent. The + * {@link com.oracle.max.graal.compiler.graph.GraphBuilder#compilation} instance is called to get an {@link com.sun.cri.ri.RiConstantPool} + * , which is C1X's interface to constant pool information. The {@link com.oracle.max.graal.compiler.graph.GraphBuilder#curBlock} field is + * set to the {@code startBlock}. + *

    + * + * Now a {@link com.oracle.max.graal.compiler.value.FrameState initialState} object is created by + * {@link com.oracle.max.graal.compiler.graph.GraphBuilder#stateAtEntry}. If the method is not static, then a {@link com.oracle.max.graal.compiler.ir.Local} + * instance is created at index 0. Since the receiver cannot be {@code null}, the + * {@link com.oracle.max.graal.compiler.ir.Value.Flag#NonNull} flag is set. Additional {@link com.oracle.max.graal.compiler.ir.Local} instances are created for the + * arguments to the method. The index is incremented by the number of slots occupied by the + * {@link com.sun.cri.ci.CiKind} corresponding to the argument type. All the {@link com.oracle.max.graal.compiler.ir.Local} instances are stored in the + * {@link com.oracle.max.graal.compiler.value.FrameState} using the {@link com.oracle.max.graal.compiler.value.FrameState#storeLocal} method. This {@link com.oracle.max.graal.compiler.value.FrameState} is then + * merged into the {@link com.oracle.max.graal.compiler.ir.BlockBegin#stateBefore} for the {@code startBlock}, which just results in a + * copy since {@code stateBefore} will be {@code null}. + *

  4. + *
  5. + * This step sets up three instance fields: {@link com.oracle.max.graal.compiler.graph.GraphBuilder#curBlock} and + * {@link com.oracle.max.graal.compiler.graph.GraphBuilder#lastInstr} to {@code startBlock} and + * {@link com.oracle.max.graal.compiler.graph.GraphBuilder#curState} to {@code initialState}. (N.B. the setting of {@code curBlock} is + * redundant as it is done in {@link com.oracle.max.graal.compiler.graph.GraphBuilder#pushRootScope}). + *
  6. + *
  7. + * Step 4 contains special handling for synchronized methods (TBD), otherwise it calls + * {@link com.oracle.max.graal.compiler.graph.GraphBuilder#finishStartBlock} which adds a {@link com.oracle.max.graal.compiler.ir.Base} block as the end of + * the {@code startBlock}. The {@link com.oracle.max.graal.compiler.ir.Base} block has one successor set to the (entry) block with flag + * {@link com.oracle.max.graal.compiler.ir.BlockBegin.BlockFlag#StandardEntry}, that was created by {@link com.oracle.max.graal.compiler.graph.BlockMap#build} (and possibly a + * successor to an OSREntry block). + *
  8. + *
  9. + * Then the {@link com.oracle.max.graal.compiler.ir.IRScope#lockStackSize} is computed. (TBD) + *
  10. + *
  11. + * Then the method is checked for being intrinsic, i.e., one that has a hard-wired implementation known to C1X. If so, + * and {@link com.oracle.max.graal.compiler.C1XOptions#OptIntrinsify} is set, an attempt is made to inline it (TBD). Otherwise, or if the + * intrinsification fails, normal processing continues by adding the entry block to the + * {@link com.oracle.max.graal.compiler.graph.ScopeData} work list (kept topologically sorted) and calling + * {@link com.oracle.max.graal.compiler.graph.GraphBuilder#iterateAllBlocks}. + *
  12. + *
  13. + * Finally there is some cleanup code for synchronized blocks and OSR compilations. + *
  14. + *
+ * + *

{@link com.oracle.max.graal.compiler.graph.GraphBuilder#iterateAllBlocks}

+ * {@link com.oracle.max.graal.compiler.graph#iterateAllBlocks} repeatedly removes a block from the work list and, if not already visited, marks it so, + * kills the current memory map, sets {@link com.oracle.max.graal.compiler.graph.GraphBuilder#curBlock}, {@link com.oracle.max.graal.compiler.graph.GraphBuilder#curState} + * and {@link com.oracle.max.graal.compiler.graph.GraphBuilder#lastInstr} and then calls + * {@link com.oracle.max.graal.compiler.graph.GraphBuilder#iterateBytecodesForBlock}. + * + * This process continues until all the blocks have been visited (processed) after which control returns to {@code + * build}. + *

+ + *

{@link com.oracle.max.graal.compiler.graph.GraphBuilder#iterateBytecodesForBlock}

+ * + * {@link com.oracle.max.graal.compiler.graph.GraphBuilder#iterateBytecodesForBlock} performs an abstract interpretation of the bytecodes in the block, appending new + * nodes as necessary, until the last added node is an instance of {@link com.oracle.max.graal.compiler.ir.BlockEnd}. (Note: It has an + * explicit check for finding a new {@link com.oracle.max.graal.compiler.ir.BlockBegin} before a {@link com.oracle.max.graal.compiler.ir.BlockEnd} but + * {@link com.oracle.max.graal.compiler.graph.BlockMap#moveSuccessorLists} has a similar check so this may be redundant). For example, + * consider the following bytecodes: + * + *
+ * 
+ *         0: iconst_0
+ *         1: istore_2
+ *         2: goto 22
+ * 
+ * 
+ * + * The {@code iconst_0} bytecode causes a {@link com.oracle.max.graal.compiler.ir.Constant} node representing zero to be pushed on the + * {@link com.oracle.max.graal.compiler.graph.GraphBuilder#curState} stack and the node to be appended to the {@link com.oracle.max.graal.compiler.ir.BlockBegin} (entry) node associated with index 0. + * The {@code istore_2} causes the node to be popped of the stack and stored in the local slot 2. No IR node is + * generated for the {@code istore_2}. The {@code goto} creates a {@link com.oracle.max.graal.compiler.ir.Goto} node which is a subclass + * of {@link com.oracle.max.graal.compiler.ir.BlockEnd}, so this terminates the iteration. As part of termination the {@link com.oracle.max.graal.compiler.ir.Goto} node is marked as the + * end node of the current block and the {@link com.oracle.max.graal.compiler.value.FrameState} is propagated to the successor node(s) by merging any + * existing {@link com.oracle.max.graal.compiler.value.FrameState} with the current state. If the target is a loop header node this involves inserting + * {@link com.oracle.max.graal.compiler.ir.Phi} nodes. Finally, the target node is added to the {@code scopeData} work list. + *

+ * + * + * @author Ben Titzer + * @author Mick Jordan + * + */ +package com.oracle.max.graal.compiler.graph; diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/AccessArray.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/AccessArray.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.ir; + +import com.oracle.max.graal.graph.*; +import com.sun.cri.ci.*; + +/** + * This the base class of all array operations. + */ +public abstract class AccessArray extends StateSplit { + + private static final int INPUT_COUNT = 1; + private static final int INPUT_ARRAY = 0; + + private static final int SUCCESSOR_COUNT = 0; + + @Override + protected int inputCount() { + return super.inputCount() + INPUT_COUNT; + } + + @Override + protected int successorCount() { + return super.successorCount() + SUCCESSOR_COUNT; + } + + /** + * The instruction that produces the array object. + */ + public Value array() { + return (Value) inputs().get(super.inputCount() + INPUT_ARRAY); + } + + public Value setArray(Value n) { + return (Value) inputs().set(super.inputCount() + INPUT_ARRAY, n); + } + + /** + * Creates a new AccessArray instruction. + * @param kind the type of the result of this instruction + * @param array the instruction that produces the array object value + * @param stateBefore the frame state before the instruction + * @param inputCount + * @param successorCount + * @param graph + */ + public AccessArray(CiKind kind, Value array, int inputCount, int successorCount, Graph graph) { + super(kind, inputCount + INPUT_COUNT, successorCount + SUCCESSOR_COUNT, graph); + setArray(array); + } + +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/AccessField.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/AccessField.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.ir; + +import java.lang.reflect.*; + +import com.oracle.max.graal.graph.*; +import com.sun.cri.ci.*; +import com.sun.cri.ri.*; + +/** + * The base class of all instructions that access fields. + */ +public abstract class AccessField extends StateSplit { + + private static final int INPUT_COUNT = 1; + private static final int INPUT_OBJECT = 0; + + private static final int SUCCESSOR_COUNT = 0; + + @Override + protected int inputCount() { + return super.inputCount() + INPUT_COUNT; + } + + @Override + protected int successorCount() { + return super.successorCount() + SUCCESSOR_COUNT; + } + + /** + * The instruction that produces the receiver object of this field access (for instance field accesses). + */ + public Value object() { + return (Value) inputs().get(super.inputCount() + INPUT_OBJECT); + } + + public Value setObject(Value n) { + return (Value) inputs().set(super.inputCount() + INPUT_OBJECT, n); + } + + protected final RiField field; + + /** + * Constructs a new access field object. + * @param kind the result kind of the access + * @param object the instruction producing the receiver object + * @param field the compiler interface representation of the field + * @param inputCount + * @param successorCount + * @param graph + */ + public AccessField(CiKind kind, Value object, RiField field, int inputCount, int successorCount, Graph graph) { + super(kind, inputCount + INPUT_COUNT, successorCount + SUCCESSOR_COUNT, graph); + this.field = field; + setObject(object); + } + + /** + * Gets the compiler interface field for this field access. + * @return the compiler interface field for this field access + */ + public RiField field() { + return field; + } + + /** + * Checks whether this field access is an access to a static field. + * @return {@code true} if this field access is to a static field + */ + public boolean isStatic() { + return Modifier.isStatic(field.accessFlags()); + } + + /** + * Checks whether the class of the field of this access is loaded. + * @return {@code true} if the class is loaded + */ + public boolean isLoaded() { + return field.isResolved(); + } + + /** + * Checks whether this field is declared volatile. + * @return {@code true} if the field is resolved and declared volatile + */ + public boolean isVolatile() { + return isLoaded() && Modifier.isVolatile(field.accessFlags()); + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/AccessIndexed.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/AccessIndexed.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.ir; + +import com.oracle.max.graal.graph.*; +import com.sun.cri.ci.*; + +/** + * The {@code AccessIndexed} class is the base class of instructions that read or write + * elements of an array. + */ +public abstract class AccessIndexed extends AccessArray { + + private static final int INPUT_COUNT = 2; + private static final int INPUT_INDEX = 0; + private static final int INPUT_LENGTH = 1; + + private static final int SUCCESSOR_COUNT = 0; + + @Override + protected int inputCount() { + return super.inputCount() + INPUT_COUNT; + } + + @Override + protected int successorCount() { + return super.successorCount() + SUCCESSOR_COUNT; + } + + /** + * The instruction producing the index into the array. + */ + public Value index() { + return (Value) inputs().get(super.inputCount() + INPUT_INDEX); + } + + public Value setIndex(Value n) { + return (Value) inputs().set(super.inputCount() + INPUT_INDEX, n); + } + + /** + * The instruction that produces the length of the array. + */ + public Value length() { + return (Value) inputs().get(super.inputCount() + INPUT_LENGTH); + } + + public Value setLength(Value n) { + return (Value) inputs().set(super.inputCount() + INPUT_LENGTH, n); + } + + private final CiKind elementType; + + /** + * Create an new AccessIndexed instruction. + * @param kind the result kind of the access + * @param array the instruction producing the array + * @param index the instruction producing the index + * @param length the instruction producing the length (used in bounds check elimination?) + * @param elementKind the type of the elements of the array + * @param stateBefore the state before executing this instruction + * @param inputCount + * @param successorCount + * @param graph + */ + AccessIndexed(CiKind kind, Value array, Value index, Value length, CiKind elementKind, int inputCount, int successorCount, Graph graph) { + super(kind, array, inputCount + INPUT_COUNT, successorCount + SUCCESSOR_COUNT, graph); + setIndex(index); + setLength(length); + this.elementType = elementKind; + } + + /** + * Gets the element type of the array. + * @return the element type + */ + public CiKind elementKind() { + return elementType; + } + +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/AccessMonitor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/AccessMonitor.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.ir; + +import com.oracle.max.graal.graph.*; +import com.sun.cri.ci.*; + +/** + * The {@code AccessMonitor} instruction is the base class of both monitor acquisition and release. + */ +public abstract class AccessMonitor extends StateSplit { + + private static final int INPUT_COUNT = 2; + private static final int INPUT_OBJECT = 0; + private static final int INPUT_LOCK_ADDRESS = 1; + + private static final int SUCCESSOR_COUNT = 0; + + @Override + protected int inputCount() { + return super.inputCount() + INPUT_COUNT; + } + + @Override + protected int successorCount() { + return super.successorCount() + SUCCESSOR_COUNT; + } + + /** + * The instruction producing the object locked or unlocked by this instruction. + */ + public Value object() { + return (Value) inputs().get(super.inputCount() + INPUT_OBJECT); + } + + public Value setObject(Value n) { + return (Value) inputs().set(super.inputCount() + INPUT_OBJECT, n); + } + + /** + * The instruction producing the address of the lock object. + */ + public Value lockAddress() { + return (Value) inputs().get(super.inputCount() + INPUT_LOCK_ADDRESS); + } + + public Value setLockAddress(Value n) { + return (Value) inputs().set(super.inputCount() + INPUT_LOCK_ADDRESS, n); + } + + /** + * The lock number of this monitor access. + */ + public final int lockNumber; + + /** + * Creates a new AccessMonitor instruction. + * + * @param object the instruction producing the object + * @param lockAddress the address of the on-stack lock object or {@code null} if the runtime does not place locks on the stack + * @param stateBefore the state before executing the monitor operation + * @param lockNumber the number of the lock being acquired + * @param inputCount + * @param successorCount + * @param graph + */ + public AccessMonitor(Value object, Value lockAddress, int lockNumber, int inputCount, int successorCount, Graph graph) { + super(CiKind.Illegal, inputCount + INPUT_COUNT, successorCount + SUCCESSOR_COUNT, graph); + this.lockNumber = lockNumber; + setObject(object); + setLockAddress(lockAddress); + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Anchor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Anchor.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.ir; + +import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.graph.*; +import com.sun.cri.ci.*; + +/** + * The {@code Anchor} instruction represents the end of a block with an unconditional jump to another block. + */ +public final class Anchor extends BlockEnd { + + private static final int INPUT_COUNT = 0; + private static final int SUCCESSOR_COUNT = 0; + + /** + * Constructs a new Anchor instruction. + * @param graph + */ + public Anchor(Graph graph) { + super(CiKind.Illegal, 1, INPUT_COUNT, SUCCESSOR_COUNT, graph); + } + + @Override + public void accept(ValueVisitor v) { + v.visitAnchor(this); + } + + @Override + public void print(LogStream out) { + out.print("anchor ").print(defaultSuccessor()); + } + + @Override + public Node copy(Graph into) { + Anchor x = new Anchor(into); + return x; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/And.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/And.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.ir; + +import com.oracle.max.graal.compiler.opt.CanonicalizerPhase.*; +import com.oracle.max.graal.graph.*; +import com.sun.cri.bytecode.*; +import com.sun.cri.ci.*; + +public final class And extends Logic { + private static final AndCanonicalizerOp CANONICALIZER = new AndCanonicalizerOp(); + + /** + * @param opcode + * @param x + * @param y + * @param graph + */ + public And(CiKind kind, Value x, Value y, Graph graph) { + super(kind, kind == CiKind.Int ? Bytecodes.IAND : Bytecodes.LAND, x, y, graph); + } + + @Override + public String shortName() { + return "&"; + } + + @Override + public Node copy(Graph into) { + And x = new And(kind, null, null, into); + return x; + } + + @SuppressWarnings("unchecked") + @Override + public T lookup(Class clazz) { + if (clazz == CanonicalizerOp.class) { + return (T) CANONICALIZER; + } + return super.lookup(clazz); + } + + private static class AndCanonicalizerOp implements CanonicalizerOp { + @Override + public Node canonical(Node node) { + assert node instanceof And; + And and = (And) node; + CiKind kind = and.kind; + Graph graph = and.graph(); + Value x = and.x(); + Value y = and.y(); + if (x == y) { + return x; + } + if (x.isConstant() && !y.isConstant()) { + and.swapOperands(); + Value t = y; + y = x; + x = t; + } + if (x.isConstant()) { + if (kind == CiKind.Int) { + return Constant.forInt(x.asConstant().asInt() & y.asConstant().asInt(), graph); + } else { + assert kind == CiKind.Long; + return Constant.forLong(x.asConstant().asLong() & y.asConstant().asLong(), graph); + } + } else if (y.isConstant()) { + if (kind == CiKind.Int) { + int c = y.asConstant().asInt(); + if (c == -1) { + return x; + } + if (c == 0) { + return Constant.forInt(0, graph); + } + } else { + assert kind == CiKind.Long; + long c = y.asConstant().asLong(); + if (c == -1) { + return x; + } + if (c == 0) { + return Constant.forLong(0, graph); + } + } + } + return and; + } + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Arithmetic.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Arithmetic.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.ir; + +import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.graph.*; +import com.sun.cri.bytecode.*; +import com.sun.cri.ci.*; + +/** + * The {@code ArithmeticOp} class represents arithmetic operations such as addition, subtraction, etc. + */ +public final class Arithmetic extends Binary { + + private static final int INPUT_COUNT = 0; + private static final int SUCCESSOR_COUNT = 0; + + private final boolean canTrap; + private final boolean isStrictFP; + + /** + * Creates a new arithmetic operation. + * @param opcode the bytecode opcode + * @param kind the result kind of the operation + * @param x the first input instruction + * @param y the second input instruction + * @param isStrictFP indicates this operation has strict rounding semantics + * @param stateBefore the state for instructions that may trap + */ + public Arithmetic(int opcode, CiKind kind, Value x, Value y, boolean isStrictFP, boolean canTrap, Graph graph) { + super(kind, opcode, x, y, INPUT_COUNT, SUCCESSOR_COUNT, graph); + this.isStrictFP = isStrictFP; + this.canTrap = canTrap; + } + + /** + * Checks whether this instruction has strict fp semantics. + * @return {@code true} if this instruction has strict fp semantics + */ + public boolean isStrictFP() { + return isStrictFP; + } + + @Override + public void accept(ValueVisitor v) { + v.visitArithmetic(this); + } + + public boolean isCommutative() { + return Bytecodes.isCommutative(opcode); + } + + @Override + public void print(LogStream out) { + out.print(x()).print(' ').print(Bytecodes.operator(opcode)).print(' ').print(y()); + } + + @Override + public String shortName() { + return Bytecodes.operator(opcode); + } + + @Override + public Node copy(Graph into) { + Arithmetic x = new Arithmetic(opcode, kind, null, null, isStrictFP, canTrap, into); + return x; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/ArrayLength.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/ArrayLength.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.ir; + +import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.compiler.util.*; +import com.oracle.max.graal.graph.*; +import com.sun.cri.bytecode.*; +import com.sun.cri.ci.*; + +/** + * The {@code ArrayLength} instruction gets the length of an array. + */ +public final class ArrayLength extends FloatingNode { + + private static final int INPUT_COUNT = 1; + private static final int INPUT_ARRAY = 0; + + private static final int SUCCESSOR_COUNT = 0; + + @Override + protected int inputCount() { + return super.inputCount() + INPUT_COUNT; + } + + @Override + protected int successorCount() { + return super.successorCount() + SUCCESSOR_COUNT; + } + + /** + * The instruction that produces the array object. + */ + public Value array() { + return (Value) inputs().get(super.inputCount() + INPUT_ARRAY); + } + + public Value setArray(Value n) { + return (Value) inputs().set(super.inputCount() + INPUT_ARRAY, n); + } + + /** + * Constructs a new ArrayLength instruction. + * @param array the instruction producing the array + * @param newFrameState the state after executing this instruction + */ + public ArrayLength(Value array, Graph graph) { + super(CiKind.Int, INPUT_COUNT, SUCCESSOR_COUNT, graph); + setArray(array); + } + + @Override + public void accept(ValueVisitor v) { + v.visitArrayLength(this); + } + + @Override + public int valueNumber() { + return Util.hash1(Bytecodes.ARRAYLENGTH, array()); + } + + @Override + public boolean valueEqual(Node i) { + if (i instanceof ArrayLength) { + ArrayLength o = (ArrayLength) i; + return array() == o.array(); + } + return false; + } + + @Override + public void print(LogStream out) { + out.print(array()).print(".length"); + } + + @Override + public Node copy(Graph into) { + ArrayLength x = new ArrayLength(null, into); + return x; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Binary.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Binary.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.ir; + +import com.oracle.max.graal.compiler.util.*; +import com.oracle.max.graal.graph.*; +import com.sun.cri.bytecode.*; +import com.sun.cri.ci.*; + +/** + * The {@code Op2} class is the base of arithmetic and logic operations with two inputs. + */ +public abstract class Binary extends FloatingNode { + + private static final int INPUT_COUNT = 2; + private static final int INPUT_X = 0; + private static final int INPUT_Y = 1; + + private static final int SUCCESSOR_COUNT = 0; + + @Override + protected int inputCount() { + return super.inputCount() + INPUT_COUNT; + } + + @Override + protected int successorCount() { + return super.successorCount() + SUCCESSOR_COUNT; + } + + /** + * The first input to this instruction. + */ + public Value x() { + return (Value) inputs().get(super.inputCount() + INPUT_X); + } + + public Value setX(Value n) { + return (Value) inputs().set(super.inputCount() + INPUT_X, n); + } + + /** + * The second input to this instruction. + */ + public Value y() { + return (Value) inputs().get(super.inputCount() + INPUT_Y); + } + + public Value setY(Value n) { + return (Value) inputs().set(super.inputCount() + INPUT_Y, n); + } + + /** + * The opcode of this instruction. + */ + public final int opcode; + + /** + * Creates a new Op2 instance. + * @param kind the result type of this instruction + * @param opcode the bytecode opcode + * @param x the first input instruction + * @param y the second input instruction + */ + public Binary(CiKind kind, int opcode, Value x, Value y, int inputCount, int successorCount, Graph graph) { + super(kind, inputCount + INPUT_COUNT, successorCount + SUCCESSOR_COUNT, graph); + this.opcode = opcode; + setX(x); + setY(y); + } + + /** + * Swaps the operands of this instruction. This is only legal for commutative operations. + */ + public void swapOperands() { + assert Bytecodes.isCommutative(opcode); + Value t = x(); + setX(y()); + setY(t); + } + + @Override + public int valueNumber() { + return Util.hash2(opcode, x(), y()); + } + + @Override + public boolean valueEqual(Node i) { + if (i instanceof Binary) { + Binary o = (Binary) i; + return opcode == o.opcode && x() == o.x() && y() == o.y(); + } + return false; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/BlockClosure.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/BlockClosure.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.ir; + +import com.oracle.max.graal.compiler.schedule.*; + +/** + * The {@code BlockClosure} interface represents a closure for iterating over blocks. + */ +public interface BlockClosure { + void apply(Block block); +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/BlockEnd.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/BlockEnd.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.ir; + +import java.util.*; + +import com.oracle.max.graal.graph.*; +import com.sun.cri.ci.*; + +/** + * The {@code BlockEnd} instruction is a base class for all instructions that end a basic + * block, including branches, switches, throws, and goto's. + */ +public abstract class BlockEnd extends Instruction { + + private static final int INPUT_COUNT = 0; + + private static final int SUCCESSOR_COUNT = 0; + private final int blockSuccessorCount; + + @Override + protected int inputCount() { + return super.inputCount() + INPUT_COUNT; + } + + @Override + protected int successorCount() { + return super.successorCount() + blockSuccessorCount + SUCCESSOR_COUNT; + } + + /** + * The list of instructions that produce input for this instruction. + */ + public Instruction blockSuccessor(int index) { + assert index >= 0 && index < blockSuccessorCount; + return (Instruction) successors().get(super.successorCount() + SUCCESSOR_COUNT + index); + } + + public Instruction setBlockSuccessor(int index, Instruction n) { + assert index >= 0 && index < blockSuccessorCount; + return (Merge) successors().set(super.successorCount() + SUCCESSOR_COUNT + index, n); + } + + public int blockSuccessorCount() { + return blockSuccessorCount; + } + + /** + * Constructs a new block end with the specified value type. + * @param kind the type of the value produced by this instruction + * @param successors the list of successor blocks. If {@code null}, a new one will be created. + */ + public BlockEnd(CiKind kind, List blockSuccessors, int inputCount, int successorCount, Graph graph) { + this(kind, blockSuccessors.size(), inputCount, successorCount, graph); + for (int i = 0; i < blockSuccessors.size(); i++) { + setBlockSuccessor(i, blockSuccessors.get(i)); + } + } + + public BlockEnd(CiKind kind, int blockSuccessorCount, int inputCount, int successorCount, Graph graph) { + super(kind, inputCount + INPUT_COUNT, successorCount + blockSuccessorCount + SUCCESSOR_COUNT, graph); + this.blockSuccessorCount = blockSuccessorCount; + } + + public BlockEnd(CiKind kind, Graph graph) { + this(kind, 2, 0, 0, graph); + } + + /** + * Gets the block begin associated with this block end. + * @return the beginning of this basic block + */ + public Merge begin() { + for (Node n : predecessors()) { + if (n instanceof Merge) { + return (Merge) n; + } + } + return null; + } + + /** + * Substitutes a successor block in this block end's successor list. Note that + * this method updates all occurrences in the list. + * @param oldSucc the old successor to replace + * @param newSucc the new successor + */ + public int substituteSuccessor(Merge oldSucc, Merge newSucc) { + assert newSucc != null; + int count = 0; + for (int i = 0; i < blockSuccessorCount; i++) { + if (blockSuccessor(i) == oldSucc) { + setBlockSuccessor(i, newSucc); + count++; + } + } + return count; + } + + /** + * Gets the successor corresponding to the default (fall through) case. + * @return the default successor + */ + public Instruction defaultSuccessor() { + return blockSuccessor(blockSuccessorCount - 1); + } + + /** + * Searches for the specified successor and returns its index into the + * successor list if found. + * @param b the block to search for in the successor list + * @return the index of the block in the list if found; -1 otherwise + */ + public int successorIndex(Merge b) { + for (int i = 0; i < blockSuccessorCount; i++) { + if (blockSuccessor(i) == b) { + return i; + } + } + return -1; + } + + /** + * Gets this block end's list of successors. + * @return the successor list + */ + @SuppressWarnings({ "unchecked", "rawtypes"}) + public List blockSuccessors() { + List list = (List) successors().subList(super.successorCount() + SUCCESSOR_COUNT, super.successorCount() + blockSuccessorCount + SUCCESSOR_COUNT); + return Collections.unmodifiableList(list); + } + + public void clearSuccessors() { + for (int i = 0; i < blockSuccessorCount(); i++) { + setBlockSuccessor(i, null); + } + } + +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/BlockList.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/BlockList.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.ir; + +import java.util.*; + +/** + * The {@code BlockList} class implements a specialized list data structure for representing + * the predecessor and successor lists of basic blocks. + */ +public class BlockList implements Iterable { + + private Merge[] array; + private int cursor; + + BlockList(int sizeHint) { + if (sizeHint > 0) { + array = new Merge[sizeHint]; + } else { + array = new Merge[2]; + } + } + + public void remove(int index) { + if (index < 0 || index >= cursor) { + throw new IndexOutOfBoundsException(); + } + for (int i = index; i < cursor; i++) { + array[i] = array[i + 1]; + } + cursor--; + } + + public void remove(Merge block) { + int j = 0; + for (int i = 0; i < cursor; i++) { + if (i != j) { + array[j] = array[i]; + } + if (array[i] != block) { + j++; + } + } + cursor = j; + } + + public void exchange(int index1, int index2) { + if (index1 < 0 || index1 >= cursor) { + throw new IndexOutOfBoundsException(); + } + if (index2 < 0 || index2 >= cursor) { + throw new IndexOutOfBoundsException(); + } + Merge t = array[index2]; + array[index2] = array[index1]; + array[index1] = t; + } + + public void insert(int index, Merge block) { + if (index < 0 || index >= cursor) { + throw new IndexOutOfBoundsException(); + } + growOne(); + for (int i = cursor; i > index; i--) { + array[i] = array[i - 1]; + } + array[cursor++] = block; + } + + public void append(Merge block) { + growOne(); + array[cursor++] = block; + } + + public Merge get(int index) { + if (index < 0 || index >= cursor) { + throw new IndexOutOfBoundsException(); + } + return array[index]; + } + + public void replace(Merge oldBlock, Merge newBlock) { + for (int i = 0; i < cursor; i++) { + if (array[i] == oldBlock) { + array[i] = newBlock; + } + } + } + + public boolean checkForSameBlock() { + if (cursor == 0) { + return true; + } + Merge b = array[0]; + for (int i = 1; i < cursor; i++) { + if (array[i] != b) { + return false; + } + } + return true; + } + + public Iterator iterator() { + return new Iter(); + } + + private void growOne() { + if (cursor == array.length) { + array = Arrays.copyOf(array, array.length * 3); + } + } + + private class Iter implements Iterator { + private int pos; + + public boolean hasNext() { + return pos < cursor; + } + + public Merge next() { + return array[pos++]; + } + + public void remove() { + BlockList.this.remove(pos); + } + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/CheckCast.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/CheckCast.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.ir; + +import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.compiler.util.*; +import com.oracle.max.graal.graph.*; +import com.sun.cri.bytecode.*; +import com.sun.cri.ci.*; +import com.sun.cri.ri.*; + +/** + * The {@code CheckCast} instruction represents a {@link Bytecodes#CHECKCAST}. + */ +public final class CheckCast extends TypeCheck { + + private static final int INPUT_COUNT = 0; + private static final int SUCCESSOR_COUNT = 0; + + /** + * Creates a new CheckCast instruction. + * @param targetClass the class being cast to + * @param object the instruction producing the object + * @param stateBefore the state before the cast + * @param graph + */ + public CheckCast(RiType targetClass, Value targetClassInstruction, Value object, Graph graph) { + super(targetClass, targetClassInstruction, object, CiKind.Object, INPUT_COUNT, SUCCESSOR_COUNT, graph); + } + + /** + * Gets the declared type of the result of this instruction. + * @return the declared type of the result + */ + @Override + public RiType declaredType() { + return targetClass; + } + + /** + * Gets the exact type of the result of this instruction. + * @return the exact type of the result + */ + @Override + public RiType exactType() { + return targetClass.isResolved() ? targetClass.exactType() : null; + } + + @Override + public void accept(ValueVisitor v) { + v.visitCheckCast(this); + } + + @Override + public int valueNumber() { + return targetClass.isResolved() ? Util.hash1(Bytecodes.CHECKCAST, object()) : 0; + } + + @Override + public boolean valueEqual(Node i) { + if (i instanceof CheckCast) { + CheckCast o = (CheckCast) i; + return targetClass == o.targetClass && object() == o.object(); + } + return false; + } + + @Override + public void print(LogStream out) { + out.print("checkcast("). + print(object()). + print(","). + print(targetClassInstruction()). + print(") "). + print(CiUtil.toJavaName(targetClass())); + } + + @Override + public Node copy(Graph into) { + CheckCast x = new CheckCast(targetClass, null, null, into); + return x; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Compare.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Compare.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.ir; + +import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.compiler.util.*; +import com.oracle.max.graal.graph.*; +import com.sun.cri.ci.*; + +public final class Compare extends FloatingNode { + + private static final int INPUT_COUNT = 2; + private static final int INPUT_X = 0; + private static final int INPUT_Y = 1; + + private static final int SUCCESSOR_COUNT = 0; + + @Override + protected int inputCount() { + return super.inputCount() + INPUT_COUNT; + } + + @Override + protected int successorCount() { + return super.successorCount() + SUCCESSOR_COUNT; + } + + /** + * The instruction that produces the first input to this comparison. + */ + public Value x() { + return (Value) inputs().get(super.inputCount() + INPUT_X); + } + + public Value setX(Value n) { + return (Value) inputs().set(super.inputCount() + INPUT_X, n); + } + + /** + * The instruction that produces the second input to this comparison. + */ + public Value y() { + return (Value) inputs().get(super.inputCount() + INPUT_Y); + } + + public Value setY(Value n) { + return (Value) inputs().set(super.inputCount() + INPUT_Y, n); + } + + Condition condition; + boolean unorderedIsTrue; + + /** + * Constructs a new If instruction. + * @param x the instruction producing the first input to the instruction + * @param condition the condition (comparison operation) + * @param y the instruction that produces the second input to this instruction + * @param graph + */ + public Compare(Value x, Condition condition, Value y, Graph graph) { + super(CiKind.Illegal, INPUT_COUNT, SUCCESSOR_COUNT, graph); + assert (x == null && y == null) || Util.archKindsEqual(x, y); + this.condition = condition; + setX(x); + setY(y); + } + + /** + * Gets the condition (comparison operation) for this instruction. + * @return the condition + */ + public Condition condition() { + return condition; + } + + /** + * Checks whether unordered inputs mean true or false. + * @return {@code true} if unordered inputs produce true + */ + public boolean unorderedIsTrue() { + return unorderedIsTrue; + } + + /** + * Swaps the operands to this if and reverses the condition (e.g. > goes to <=). + * @see Condition#mirror() + */ + public void swapOperands() { + condition = condition.mirror(); + Value t = x(); + setX(y()); + setY(t); + } + + @Override + public void accept(ValueVisitor v) { + } + + @Override + public void print(LogStream out) { + out.print("comp "). + print(x()). + print(' '). + print(condition().operator). + print(' '). + print(y()); + } + + @Override + public String shortName() { + return "Comp " + condition.operator; + } + + @Override + public Node copy(Graph into) { + Compare x = new Compare(null, condition, null, into); + x.unorderedIsTrue = unorderedIsTrue; + return x; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/ComputeLinearScanOrder.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/ComputeLinearScanOrder.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,590 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.max.graal.compiler.ir; + +import java.util.*; + +import com.oracle.max.graal.compiler.*; +import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.compiler.lir.*; +import com.oracle.max.graal.compiler.util.*; +import com.sun.cri.ci.*; + +public final class ComputeLinearScanOrder { + + private final int maxBlockId; // the highest blockId of a block + private int numBlocks; // total number of blocks (smaller than maxBlockId) + private int numLoops; // total number of loops + private boolean iterativeDominators; // method requires iterative computation of dominators + + List linearScanOrder; // the resulting list of blocks in correct order + + final CiBitMap visitedBlocks; // used for recursive processing of blocks + final CiBitMap activeBlocks; // used for recursive processing of blocks + final CiBitMap dominatorBlocks; // temporary BitMap used for computation of dominator + final int[] forwardBranches; // number of incoming forward branches for each block + final List loopEndBlocks; // list of all loop end blocks collected during countEdges + BitMap2D loopMap; // two-dimensional bit set: a bit is set if a block is contained in a loop + final List workList; // temporary list (used in markLoops and computeOrder) + + // accessors for visitedBlocks and activeBlocks + void initVisited() { + activeBlocks.clearAll(); + visitedBlocks.clearAll(); + } + + boolean isVisited(LIRBlock b) { + return visitedBlocks.get(b.blockID()); + } + + boolean isActive(LIRBlock b) { + return activeBlocks.get(b.blockID()); + } + + void setVisited(LIRBlock b) { + assert !isVisited(b) : "already set"; + visitedBlocks.set(b.blockID()); + } + + void setActive(LIRBlock b) { + assert !isActive(b) : "already set"; + activeBlocks.set(b.blockID()); + } + + void clearActive(LIRBlock b) { + assert isActive(b) : "not already"; + activeBlocks.clear(b.blockID()); + } + + // accessors for forwardBranches + void incForwardBranches(LIRBlock b) { + forwardBranches[b.blockID()]++; + } + + int decForwardBranches(LIRBlock b) { + return --forwardBranches[b.blockID()]; + } + + // accessors for loopMap + boolean isBlockInLoop(int loopIdx, LIRBlock b) { + return loopMap.at(loopIdx, b.blockID()); + } + + void setBlockInLoop(int loopIdx, LIRBlock b) { + loopMap.setBit(loopIdx, b.blockID()); + } + + void clearBlockInLoop(int loopIdx, int blockId) { + loopMap.clearBit(loopIdx, blockId); + } + + // accessors for final result + public List linearScanOrder() { + return linearScanOrder; + } + + public int numLoops() { + return numLoops; + } + + public ComputeLinearScanOrder(int maxBlockId, LIRBlock startBlock) { + + this.maxBlockId = maxBlockId; + visitedBlocks = new CiBitMap(maxBlockId); + activeBlocks = new CiBitMap(maxBlockId); + dominatorBlocks = new CiBitMap(maxBlockId); + forwardBranches = new int[maxBlockId]; + loopEndBlocks = new ArrayList(8); + workList = new ArrayList(8); + + splitCriticalEdges(); + + countEdges(startBlock, null); + + if (numLoops > 0) { + markLoops(); + clearNonNaturalLoops(startBlock); + assignLoopDepth(startBlock); + } + + computeOrder(startBlock); + + printBlocks(); + assert verify(); + } + + void splitCriticalEdges() { + // TODO: move critical edge splitting from IR to here + } + + /** + * Traverses the CFG to analyze block and edge info. The analysis performed is: + * + * 1. Count of total number of blocks. + * 2. Count of all incoming edges and backward incoming edges. + * 3. Number loop header blocks. + * 4. Create a list with all loop end blocks. + */ + void countEdges(LIRBlock cur, LIRBlock parent) { + if (C1XOptions.TraceLinearScanLevel >= 3) { + TTY.println("Counting edges for block B%d%s", cur.blockID(), parent == null ? "" : " coming from B" + parent.blockID()); + } + + if (isActive(cur)) { + if (C1XOptions.TraceLinearScanLevel >= 3) { + TTY.println("backward branch"); + } + assert isVisited(cur) : "block must be visited when block is active"; + assert parent != null : "must have parent"; + + cur.setLinearScanLoopHeader(); + parent.setLinearScanLoopEnd(); + + loopEndBlocks.add(parent); + return; + } + + // increment number of incoming forward branches + incForwardBranches(cur); + + if (isVisited(cur)) { + if (C1XOptions.TraceLinearScanLevel >= 3) { + TTY.println("block already visited"); + } + return; + } + + numBlocks++; + setVisited(cur); + setActive(cur); + + // recursive call for all successors + int i; + for (i = cur.numberOfSux() - 1; i >= 0; i--) { + countEdges(cur.suxAt(i), cur); + } + + clearActive(cur); + + // Each loop has a unique number. + // When multiple loops are nested, assignLoopDepth assumes that the + // innermost loop has the lowest number. This is guaranteed by setting + // the loop number after the recursive calls for the successors above + // have returned. + if (cur.isLinearScanLoopHeader()) { + assert cur.loopIndex() == -1 : "cannot set loop-index twice"; + if (C1XOptions.TraceLinearScanLevel >= 3) { + TTY.println("Block B%d is loop header of loop %d", cur.blockID(), numLoops); + } + + cur.setLoopIndex(numLoops); + numLoops++; + } + + if (C1XOptions.TraceLinearScanLevel >= 3) { + TTY.println("Finished counting edges for block B%d", cur.blockID()); + } + } + + void markLoops() { + if (C1XOptions.TraceLinearScanLevel >= 3) { + TTY.println("----- marking loops"); + } + + loopMap = new BitMap2D(numLoops, maxBlockId); + + for (int i = loopEndBlocks.size() - 1; i >= 0; i--) { + LIRBlock loopEnd = loopEndBlocks.get(i); + LIRBlock loopStart = loopEnd.suxAt(0); + int loopIdx = loopStart.loopIndex(); + + if (C1XOptions.TraceLinearScanLevel >= 3) { + TTY.println("Processing loop from B%d to B%d (loop %d):", loopStart.blockID(), loopEnd.blockID(), loopIdx); + } + assert loopEnd.isLinearScanLoopEnd() : "loop end flag must be set"; +// assert loopEnd.numberOfSux() == 1 : "incorrect number of successors"; + assert loopStart.isLinearScanLoopHeader() : "loop header flag must be set"; + assert loopIdx >= 0 && loopIdx < numLoops : "loop index not set"; + assert workList.isEmpty() : "work list must be empty before processing"; + + // add the end-block of the loop to the working list + workList.add(loopEnd); + setBlockInLoop(loopIdx, loopEnd); + do { + LIRBlock cur = workList.remove(workList.size() - 1); + + if (C1XOptions.TraceLinearScanLevel >= 3) { + TTY.println(" processing B%d", cur.blockID()); + } + assert isBlockInLoop(loopIdx, cur) : "bit in loop map must be set when block is in work list"; + + // recursive processing of all predecessors ends when start block of loop is reached + if (cur != loopStart) { + for (int j = cur.numberOfPreds() - 1; j >= 0; j--) { + LIRBlock pred = cur.predAt(j); + + if (!isBlockInLoop(loopIdx, pred)) { + // this predecessor has not been processed yet, so add it to work list + if (C1XOptions.TraceLinearScanLevel >= 3) { + TTY.println(" pushing B%d", pred.blockID()); + } + workList.add(pred); + setBlockInLoop(loopIdx, pred); + } + } + } + } while (!workList.isEmpty()); + } + } + + // check for non-natural loops (loops where the loop header does not dominate + // all other loop blocks = loops with multiple entries). + // such loops are ignored + void clearNonNaturalLoops(LIRBlock startBlock) { + for (int i = numLoops - 1; i >= 0; i--) { + if (isBlockInLoop(i, startBlock)) { + // loop i contains the entry block of the method. + // this is not a natural loop, so ignore it + if (C1XOptions.TraceLinearScanLevel >= 2) { + TTY.println("Loop %d is non-natural, so it is ignored", i); + } + + for (int blockId = maxBlockId - 1; blockId >= 0; blockId--) { + clearBlockInLoop(i, blockId); + } + iterativeDominators = true; + } + } + } + + void assignLoopDepth(LIRBlock startBlock) { + if (C1XOptions.TraceLinearScanLevel >= 3) { + TTY.println("----- computing loop-depth and weight"); + } + initVisited(); + + assert workList.isEmpty() : "work list must be empty before processing"; + workList.add(startBlock); + + do { + LIRBlock cur = workList.remove(workList.size() - 1); + + if (!isVisited(cur)) { + setVisited(cur); + if (C1XOptions.TraceLinearScanLevel >= 4) { + TTY.println("Computing loop depth for block B%d", cur.blockID()); + } + + // compute loop-depth and loop-index for the block + assert cur.loopDepth() == 0 : "cannot set loop-depth twice"; + int i; + int loopDepth = 0; + int minLoopIdx = -1; + for (i = numLoops - 1; i >= 0; i--) { + if (isBlockInLoop(i, cur)) { + loopDepth++; + minLoopIdx = i; + } + } + cur.setLoopDepth(loopDepth); + cur.setLoopIndex(minLoopIdx); + + // append all unvisited successors to work list + for (i = cur.numberOfSux() - 1; i >= 0; i--) { + workList.add(cur.suxAt(i)); + } + } + } while (!workList.isEmpty()); + } + + int computeWeight(LIRBlock cur) { + LIRBlock singleSux = null; + if (cur.numberOfSux() == 1) { + singleSux = cur.suxAt(0); + } + + // limit loop-depth to 15 bit (only for security reason, it will never be so big) + int weight = (cur.loopDepth() & 0x7FFF) << 16; + + int curBit = 15; + + // this is necessary for the (very rare) case that two successive blocks have + // the same loop depth, but a different loop index (can happen for endless loops + // with exception handlers) + if (!cur.isLinearScanLoopHeader()) { + weight |= 1 << curBit; + } + curBit--; + + // loop end blocks (blocks that end with a backward branch) are added + // after all other blocks of the loop. + if (!cur.isLinearScanLoopEnd()) { + weight |= 1 << curBit; + } + curBit--; + + // critical edge split blocks are preferred because then they have a greater + // probability to be completely empty + //if (cur.isCriticalEdgeSplit()) { + // weight |= 1 << curBit; + //} + //curBit--; + + // exceptions should not be thrown in normal control flow, so these blocks + // are added as late as possible +// if (!(cur.end() instanceof Throw) && (singleSux == null || !(singleSux.end() instanceof Throw))) { +// weight |= 1 << curBit; +// } +// curBit--; +// if (!(cur.end() instanceof Return) && (singleSux == null || !(singleSux.end() instanceof Return))) { +// weight |= 1 << curBit; +// } +// curBit--; + + // exceptions handlers are added as late as possible +// if (!cur.isExceptionEntry()) { +// weight |= 1 << curBit; +// } +// curBit--; + + // guarantee that weight is > 0 + weight |= 1; + + assert curBit >= 0 : "too many flags"; + assert weight > 0 : "weight cannot become negative"; + + return weight; + } + + boolean readyForProcessing(LIRBlock cur) { + // Discount the edge just traveled. + // When the number drops to zero, all forward branches were processed + if (decForwardBranches(cur) != 0) { + return false; + } + + assert !linearScanOrder.contains(cur) : "block already processed (block can be ready only once)"; + assert !workList.contains(cur) : "block already in work-list (block can be ready only once)"; + return true; + } + + void sortIntoWorkList(LIRBlock cur) { + assert !workList.contains(cur) : "block already in work list"; + + int curWeight = computeWeight(cur); + + // the linearScanNumber is used to cache the weight of a block + cur.setLinearScanNumber(curWeight); + + if (C1XOptions.StressLinearScan) { + workList.add(0, cur); + return; + } + + workList.add(null); // provide space for new element + + int insertIdx = workList.size() - 1; + while (insertIdx > 0 && workList.get(insertIdx - 1).linearScanNumber() > curWeight) { + workList.set(insertIdx, workList.get(insertIdx - 1)); + insertIdx--; + } + workList.set(insertIdx, cur); + + if (C1XOptions.TraceLinearScanLevel >= 3) { + TTY.println("Sorted B%d into worklist. new worklist:", cur.blockID()); + for (int i = 0; i < workList.size(); i++) { + TTY.println(String.format("%8d B%02d weight:%6x", i, workList.get(i).blockID(), workList.get(i).linearScanNumber())); + } + } + + for (int i = 0; i < workList.size(); i++) { + assert workList.get(i).linearScanNumber() > 0 : "weight not set"; + assert i == 0 || workList.get(i - 1).linearScanNumber() <= workList.get(i).linearScanNumber() : "incorrect order in worklist"; + } + } + + void appendBlock(LIRBlock cur) { + if (C1XOptions.TraceLinearScanLevel >= 3) { + TTY.println("appending block B%d (weight 0x%06x) to linear-scan order", cur.blockID(), cur.linearScanNumber()); + } + assert !linearScanOrder.contains(cur) : "cannot add the same block twice"; + + // currently, the linear scan order and code emit order are equal. + // therefore the linearScanNumber and the weight of a block must also + // be equal. + cur.setLinearScanNumber(linearScanOrder.size()); + linearScanOrder.add(cur); + } + + void computeOrder(LIRBlock startBlock) { + if (C1XOptions.TraceLinearScanLevel >= 3) { + TTY.println("----- computing final block order"); + } + + // the start block is always the first block in the linear scan order + linearScanOrder = new ArrayList(numBlocks); +// appendBlock(startBlock); + + LIRBlock stdEntry = startBlock; //.suxAt(0); + + // start processing with standard entry block + assert workList.isEmpty() : "list must be empty before processing"; + + if (readyForProcessing(stdEntry)) { + sortIntoWorkList(stdEntry); + } else { + throw new CiBailout("the stdEntry must be ready for processing (otherwise, the method has no start block)"); + } + + do { + LIRBlock cur = workList.remove(workList.size() - 1); + + appendBlock(cur); + + int i; + int numSux = cur.numberOfSux(); + // changed loop order to get "intuitive" order of if- and else-blocks + for (i = 0; i < numSux; i++) { + LIRBlock sux = cur.suxAt(i); + if (readyForProcessing(sux)) { + sortIntoWorkList(sux); + } + } + } while (workList.size() > 0); + } + + public void printBlocks() { + if (C1XOptions.TraceLinearScanLevel >= 2) { + TTY.println("----- loop information:"); + for (LIRBlock cur : linearScanOrder) { + TTY.print(String.format("%4d: B%02d: ", cur.linearScanNumber(), cur.blockID())); + for (int loopIdx = 0; loopIdx < numLoops; loopIdx++) { + TTY.print(String.format("%d = %b ", loopIdx, isBlockInLoop(loopIdx, cur))); + } + TTY.println(String.format(" . loopIndex: %2d, loopDepth: %2d", cur.loopIndex(), cur.loopDepth())); + } + } + + if (C1XOptions.TraceLinearScanLevel >= 1) { + TTY.println("----- linear-scan block order:"); + for (LIRBlock cur : linearScanOrder) { + TTY.print(String.format("%4d: B%02d loop: %2d depth: %2d", cur.linearScanNumber(), cur.blockID(), cur.loopIndex(), cur.loopDepth())); + + TTY.print(cur.isLinearScanLoopHeader() ? " lh" : " "); + TTY.print(cur.isLinearScanLoopEnd() ? " le" : " "); + + TTY.print(" dom: null "); + + + if (cur.numberOfPreds() > 0) { + TTY.print(" preds: "); + for (int j = 0; j < cur.numberOfPreds(); j++) { + LIRBlock pred = cur.predAt(j); + TTY.print("B%d ", pred.blockID()); + } + } + if (cur.numberOfSux() > 0) { + TTY.print(" sux: "); + for (int j = 0; j < cur.numberOfSux(); j++) { + LIRBlock sux = cur.suxAt(j); + TTY.print("B%d ", sux.blockID()); + } + } + TTY.println(); + } + } + } + + boolean verify() { + /* assert linearScanOrder.size() == numBlocks : "wrong number of blocks in list"; + + if (C1XOptions.StressLinearScan) { + // blocks are scrambled when StressLinearScan is used + return true; + } + + // check that all successors of a block have a higher linear-scan-number + // and that all predecessors of a block have a lower linear-scan-number + // (only backward branches of loops are ignored) + int i; + for (i = 0; i < linearScanOrder.size(); i++) { + BlockBegin cur = linearScanOrder.get(i); + + assert cur.linearScanNumber() == i : "incorrect linearScanNumber"; + assert cur.linearScanNumber() >= 0 && cur.linearScanNumber() == linearScanOrder.indexOf(cur) : "incorrect linearScanNumber"; + + for (BlockBegin sux : cur.end().successors()) { + assert sux.linearScanNumber() >= 0 && sux.linearScanNumber() == linearScanOrder.indexOf(sux) : "incorrect linearScanNumber"; + if (!cur.checkBlockFlag(BlockBegin.BlockFlag.LinearScanLoopEnd)) { + assert cur.linearScanNumber() < sux.linearScanNumber() : "invalid order"; + } + if (cur.loopDepth() == sux.loopDepth()) { + assert cur.loopIndex() == sux.loopIndex() || sux.checkBlockFlag(BlockBegin.BlockFlag.LinearScanLoopHeader) : "successing blocks with same loop depth must have same loop index"; + } + } + + for (BlockBegin pred : cur.predecessors()) { + assert pred.linearScanNumber() >= 0 && pred.linearScanNumber() == linearScanOrder.indexOf(pred) : "incorrect linearScanNumber"; + if (!cur.checkBlockFlag(BlockBegin.BlockFlag.LinearScanLoopHeader)) { + assert cur.linearScanNumber() > pred.linearScanNumber() : "invalid order"; + } + if (cur.loopDepth() == pred.loopDepth()) { + assert cur.loopIndex() == pred.loopIndex() || cur.checkBlockFlag(BlockBegin.BlockFlag.LinearScanLoopHeader) : "successing blocks with same loop depth must have same loop index"; + } + + assert cur.dominator().linearScanNumber() <= pred.linearScanNumber() : "dominator must be before predecessors"; + } + + // check dominator + if (i == 0) { + assert cur.dominator() == null : "first block has no dominator"; + } else { + assert cur.dominator() != null : "all but first block must have dominator"; + } + assert cur.numberOfPreds() != 1 || cur.dominator() == cur.predAt(0) || cur.isExceptionEntry() : "Single predecessor must also be dominator"; + } + + // check that all loops are continuous + for (int loopIdx = 0; loopIdx < numLoops; loopIdx++) { + int blockIdx = 0; + assert !isBlockInLoop(loopIdx, linearScanOrder.get(blockIdx)) : "the first block must not be present in any loop"; + + // skip blocks before the loop + while (blockIdx < numBlocks && !isBlockInLoop(loopIdx, linearScanOrder.get(blockIdx))) { + blockIdx++; + } + // skip blocks of loop + while (blockIdx < numBlocks && isBlockInLoop(loopIdx, linearScanOrder.get(blockIdx))) { + blockIdx++; + } + // after the first non-loop block : there must not be another loop-block + while (blockIdx < numBlocks) { + assert !isBlockInLoop(loopIdx, linearScanOrder.get(blockIdx)) : "loop not continuous in linear-scan order"; + blockIdx++; + } + } +*/ + return true; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Condition.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Condition.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,206 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.ir; + +import com.sun.cri.bytecode.Bytecodes.*; +import com.sun.cri.ci.*; +import com.sun.cri.ri.*; + +/** + * Condition codes used in conditionals. + */ +public enum Condition { + /** + * Equal. + */ + EQ("=="), + + /** + * Not equal. + */ + NE("!="), + + /** + * Signed less than. + */ + LT("<"), + + /** + * Signed less than or equal. + */ + LE("<="), + + /** + * Signed greater than. + */ + GT(">"), + + /** + * Signed greater than or equal. + */ + GE(">="), + + /** + * Unsigned greater than or equal ("above than or equal"). + */ + AE("|>=|"), + + /** + * Unsigned less than or equal ("below than or equal"). + */ + BE("|<=|"), + + /** + * Unsigned greater than ("above than"). + */ + AT("|>|"), + + /** + * Unsigned less than ("below than"). + */ + BT("|<|"), + + TRUE("TRUE"); + + public final String operator; + + private Condition(String operator) { + this.operator = operator; + } + + public boolean check(int left, int right) { + switch (this) { + case EQ: return left == right; + case NE: return left != right; + case LT: return left < right; + case LE: return left <= right; + case GT: return left > right; + case GE: return left >= right; + case BT: return (left & 0xffffffffL) < (right & 0xffffffffL); + case BE: return (left & 0xffffffffL) <= (right & 0xffffffffL); + case AT: return (left & 0xffffffffL) > (right & 0xffffffffL); + case AE: return (left & 0xffffffffL) >= (right & 0xffffffffL); + } + throw new IllegalArgumentException(); + } + + /** + * Negate this conditional. + * @return the condition that represents the negation + */ + public final Condition negate() { + switch (this) { + case EQ: return NE; + case NE: return EQ; + case LT: return GE; + case LE: return GT; + case GT: return LE; + case GE: return LT; + case BT: return AE; + case BE: return AT; + case AT: return BE; + case AE: return BT; + } + throw new IllegalArgumentException(); + } + + /** + * Mirror this conditional (i.e. commute "a op b" to "b op' a") + * @return the condition representing the equivalent commuted operation + */ + public final Condition mirror() { + switch (this) { + case EQ: return EQ; + case NE: return NE; + case LT: return GT; + case LE: return GE; + case GT: return LT; + case GE: return LE; + case BT: return AT; + case BE: return AE; + case AT: return BT; + case AE: return BE; + } + throw new IllegalArgumentException(); + } + + /** + * Checks if this conditional operation is commutative. + * @return {@code true} if this operation is commutative + */ + public final boolean isCommutative() { + return this == EQ || this == NE; + } + + /** + * Attempts to fold a comparison between two constants and return the result. + * @param lt the constant on the left side of the comparison + * @param rt the constant on the right side of the comparison + * @param runtime the RiRuntime (might be needed to compare runtime-specific types) + * @return {@link Boolean#TRUE} if the comparison is known to be true, + * {@link Boolean#FALSE} if the comparison is known to be false, {@code null} otherwise. + */ + public Boolean foldCondition(CiConstant lt, CiConstant rt, RiRuntime runtime) { + switch (lt.kind) { + case Int: { + int x = lt.asInt(); + int y = rt.asInt(); + switch (this) { + case EQ: return x == y; + case NE: return x != y; + case LT: return x < y; + case LE: return x <= y; + case GT: return x > y; + case GE: return x >= y; + case AE: return UnsignedComparisons.aboveOrEqual(x, y); + case BE: return UnsignedComparisons.belowOrEqual(x, y); + case AT: return UnsignedComparisons.aboveThan(x, y); + case BT: return UnsignedComparisons.belowThan(x, y); + } + break; + } + case Long: { + long x = lt.asLong(); + long y = rt.asLong(); + switch (this) { + case EQ: return x == y; + case NE: return x != y; + case LT: return x < y; + case LE: return x <= y; + case GT: return x > y; + case GE: return x >= y; + } + break; + } + case Object: { + switch (this) { + case EQ: return runtime.areConstantObjectsEqual(lt, rt); + case NE: return !runtime.areConstantObjectsEqual(lt, rt); + } + break; + } + // XXX: folding of floating comparisons should be possible + } + return null; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Conditional.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Conditional.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.ir; + +import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.compiler.util.*; +import com.oracle.max.graal.graph.*; +import com.sun.cri.bytecode.*; +import com.sun.cri.ci.*; + +/** + * The {@code IfOp} class represents a comparison that yields one of two values. + * Note that these nodes are not built directly from the bytecode but are introduced + * by conditional expression elimination. + */ +public final class Conditional extends Binary { + + private static final int INPUT_COUNT = 2; + private static final int INPUT_TRUE_VALUE = 0; + private static final int INPUT_FALSE_VALUE = 1; + + private static final int SUCCESSOR_COUNT = 0; + + @Override + protected int inputCount() { + return super.inputCount() + INPUT_COUNT; + } + + @Override + protected int successorCount() { + return super.successorCount() + SUCCESSOR_COUNT; + } + + + /** + * The instruction that produces the value if the comparison is true. + */ + public Value trueValue() { + return (Value) inputs().get(super.inputCount() + INPUT_TRUE_VALUE); + } + + public Value setTrueValue(Value n) { + return (Value) inputs().set(super.inputCount() + INPUT_TRUE_VALUE, n); + } + + /** + * The instruction that produces the value if the comparison is false. + */ + public Value falseValue() { + return (Value) inputs().get(super.inputCount() + INPUT_FALSE_VALUE); + } + + public Value setFalseValue(Value n) { + return (Value) inputs().set(super.inputCount() + INPUT_FALSE_VALUE, n); + } + + + Condition condition; + + /** + * Constructs a new IfOp. + * @param x the instruction producing the first value to be compared + * @param condition the condition of the comparison + * @param y the instruction producing the second value to be compared + * @param trueValue the value produced if the condition is true + * @param falseValue the value produced if the condition is false + */ + public Conditional(Value x, Condition condition, Value y, Value trueValue, Value falseValue, Graph graph) { + // TODO: return the appropriate bytecode IF_ICMPEQ, etc + super(trueValue.kind.meet(falseValue.kind), Bytecodes.ILLEGAL, x, y, INPUT_COUNT, SUCCESSOR_COUNT, graph); + this.condition = condition; + setTrueValue(trueValue); + setFalseValue(falseValue); + } + + // for copying + private Conditional(CiKind kind, Condition cond, Graph graph) { + super(kind, Bytecodes.ILLEGAL, null, null, INPUT_COUNT, SUCCESSOR_COUNT, graph); + this.condition = cond; + } + + /** + * Gets the condition of this if operation. + * @return the condition + */ + public Condition condition() { + return condition; + } + + /** + * Checks whether this comparison operator is commutative (i.e. it is either == or !=). + * @return {@code true} if this comparison is commutative + */ + public boolean isCommutative() { + return condition == Condition.EQ || condition == Condition.NE; + } + + @Override + public void accept(ValueVisitor v) { + v.visitIfOp(this); + } + + @Override + public int valueNumber() { + return Util.hash4(condition.hashCode(), x(), y(), trueValue(), falseValue()); + } + + @Override + public boolean valueEqual(Node i) { + if (i instanceof Conditional) { + Conditional o = (Conditional) i; + return opcode == o.opcode && x() == o.x() && y() == o.y() && trueValue() == o.trueValue() && falseValue() == o.falseValue(); + } + return false; + } + + @Override + public void print(LogStream out) { + out.print(x()). + print(' '). + print(condition().operator). + print(' '). + print(y()). + print(" ? "). + print(trueValue()). + print(" : "). + print(falseValue()); + } + + @Override + public Node copy(Graph into) { + Conditional x = new Conditional(kind, condition, into); + return x; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Constant.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Constant.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.ir; + +import static com.oracle.max.graal.compiler.C1XCompilation.*; + +import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.graph.*; +import com.sun.cri.ci.*; +import com.sun.cri.ri.*; + +/** + * The {@code Constant} instruction represents a constant such as an integer value, + * long, float, object reference, address, etc. + */ +public final class Constant extends FloatingNode { + + private static final int INPUT_COUNT = 0; + private static final int SUCCESSOR_COUNT = 0; + + public final CiConstant value; + + /** + * Constructs a new instruction representing the specified constant. + * @param value the constant + * @param graph + */ + public Constant(CiConstant value, Graph graph) { + super(value.kind.stackKind(), INPUT_COUNT, SUCCESSOR_COUNT, graph); + this.value = value; + } + + @Override + public void accept(ValueVisitor v) { + v.visitConstant(this); + } + + /** + * Creates an instruction for a double constant. + * @param d the double value for which to create the instruction + * @param graph + * @return an instruction representing the double + */ + public static Constant forDouble(double d, Graph graph) { + return new Constant(CiConstant.forDouble(d), graph); + } + + /** + * Creates an instruction for a float constant. + * @param f the float value for which to create the instruction + * @return an instruction representing the float + */ + public static Constant forFloat(float f, Graph graph) { + return new Constant(CiConstant.forFloat(f), graph); + } + + /** + * Creates an instruction for an long constant. + * @param i the long value for which to create the instruction + * @return an instruction representing the long + */ + public static Constant forLong(long i, Graph graph) { + return new Constant(CiConstant.forLong(i), graph); + } + + /** + * Creates an instruction for an integer constant. + * @param i the integer value for which to create the instruction + * @return an instruction representing the integer + */ + public static Constant forInt(int i, Graph graph) { + return new Constant(CiConstant.forInt(i), graph); + } + + /** + * Creates an instruction for a boolean constant. + * @param i the boolean value for which to create the instruction + * @return an instruction representing the boolean + */ + public static Constant forBoolean(boolean i, Graph graph) { + return new Constant(CiConstant.forBoolean(i), graph); + } + + /** + * Creates an instruction for an address (jsr/ret address) constant. + * @param i the address value for which to create the instruction + * @return an instruction representing the address + */ + public static Constant forJsr(int i, Graph graph) { + return new Constant(CiConstant.forJsr(i), graph); + } + + /** + * Creates an instruction for an object constant. + * @param o the object value for which to create the instruction + * @return an instruction representing the object + */ + public static Constant forObject(Object o, Graph graph) { + return new Constant(CiConstant.forObject(o), graph); + } + + /** + * Creates an instruction for a word constant. + * @param val the word value for which to create the instruction + * @return an instruction representing the word + */ + public static Constant forWord(long val, Graph graph) { + return new Constant(CiConstant.forWord(val), graph); + } + + public static Constant defaultForKind(CiKind kind, Graph graph) { + switch(kind) { + case Boolean: + return Constant.forBoolean(false, graph); + case Byte: + case Char: + case Short: + case Int: + return Constant.forInt(0, graph); + case Double: + return Constant.forDouble(0.0, graph); + case Float: + return Constant.forFloat(0.0f, graph); + case Long: + return Constant.forLong(0L, graph); + case Object: + return Constant.forObject(null, graph); + case Word: + return Constant.forWord(0L, graph); + default: + return null; + } + } + + @Override + public String toString() { + return super.toString() + "(" + value + ")"; + } + + @Override + public int valueNumber() { + return 0x50000000 | value.hashCode(); + } + + @Override + public boolean valueEqual(Node i) { + return i instanceof Constant && ((Constant) i).value.equivalent(this.value); + } + + @Override + public RiType declaredType() { + RiRuntime runtime = compilation().runtime; + if (kind.isPrimitive()) { + runtime.asRiType(kind); + } + return runtime.getTypeOf(asConstant()); + } + + @Override + public RiType exactType() { + return declaredType(); + } + + @Override + public void print(LogStream out) { + out.print(value.valueString()); + } + + @Override + public String shortName() { + return value.name(); + } + + @Override + public Node copy(Graph into) { + Constant x = new Constant(value, into); + return x; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Convert.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Convert.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.ir; + +import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.compiler.util.*; +import com.oracle.max.graal.graph.*; +import com.sun.cri.bytecode.*; +import com.sun.cri.ci.*; + +/** + * The {@code Convert} class represents a conversion between primitive types. + */ +public final class Convert extends FloatingNode { + + private static final int INPUT_COUNT = 1; + private static final int INPUT_VALUE = 0; + + private static final int SUCCESSOR_COUNT = 0; + + @Override + protected int inputCount() { + return super.inputCount() + INPUT_COUNT; + } + + @Override + protected int successorCount() { + return super.successorCount() + SUCCESSOR_COUNT; + } + + /** + * The instruction which produces the input value to this instruction. + */ + public Value value() { + return (Value) inputs().get(super.inputCount() + INPUT_VALUE); + } + + public Value setValue(Value n) { + return (Value) inputs().set(super.inputCount() + INPUT_VALUE, n); + } + + /** + * The opcode for this conversion operation. + */ + public final int opcode; + + /** + * Constructs a new Convert instance. + * @param opcode the bytecode representing the operation + * @param value the instruction producing the input value + * @param kind the result type of this instruction + * @param graph + */ + public Convert(int opcode, Value value, CiKind kind, Graph graph) { + super(kind, INPUT_COUNT, SUCCESSOR_COUNT, graph); + this.opcode = opcode; + setValue(value); + } + + @Override + public void accept(ValueVisitor v) { + v.visitConvert(this); + } + + @Override + public int valueNumber() { + return Util.hash1(opcode, value()); + } + + @Override + public boolean valueEqual(Node i) { + if (i instanceof Convert) { + Convert o = (Convert) i; + return opcode == o.opcode && value() == o.value(); + } + return false; + } + + @Override + public void print(LogStream out) { + out.print(Bytecodes.nameOf(opcode)).print('(').print(value()).print(')'); + } + + @Override + public Node copy(Graph into) { + Convert x = new Convert(opcode, null, kind, into); + return x; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Deoptimize.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Deoptimize.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.ir; + +import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.graph.*; +import com.sun.cri.ci.*; + +public class Deoptimize extends Instruction { + + private static final int INPUT_COUNT = 0; + private static final int SUCCESSOR_COUNT = 0; + + private String message; + + public Deoptimize(Graph graph) { + super(CiKind.Illegal, INPUT_COUNT, SUCCESSOR_COUNT, graph); + } + + public void setMessage(String message) { + this.message = message; + } + + public String message() { + return message; + } + + @Override + public void accept(ValueVisitor v) { + v.visitDeoptimize(this); + } + + @Override + public void print(LogStream out) { + out.print("deoptimize"); + } + + @Override + public String shortName() { + return message == null ? "Deopt " : "Deopt " + message; + } + + @Override + public Node copy(Graph into) { + Deoptimize x = new Deoptimize(into); + x.setMessage(message); + return x; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/ExceptionDispatch.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/ExceptionDispatch.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.ir; + +import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.graph.*; +import com.sun.cri.ci.*; +import com.sun.cri.ri.*; + +/** + * This instruction takes an exception object and has two successors: + * The catchSuccessor is called whenever the exception matches the given type, otherwise otherSuccessor is called. + */ +public final class ExceptionDispatch extends BlockEnd { + + private static final int INPUT_COUNT = 1; + private static final int INPUT_EXCEPTION = 0; + + private static final int SUCCESSOR_COUNT = 0; + + @Override + protected int inputCount() { + return super.inputCount() + INPUT_COUNT; + } + + @Override + protected int successorCount() { + return super.successorCount() + SUCCESSOR_COUNT; + } + + /** + * The instruction producing the exception object. + */ + public Value exception() { + return (Value) inputs().get(super.inputCount() + INPUT_EXCEPTION); + } + + public Value setException(Value n) { + return (Value) inputs().set(super.inputCount() + INPUT_EXCEPTION, n); + } + + private final RiType catchType; + + /** + * Constructs a new ExceptionDispatch instruction. + */ + public ExceptionDispatch(Value exception, Instruction catchSuccessor, Instruction otherSuccessor, RiType catchType, Graph graph) { + super(CiKind.Int, 2, INPUT_COUNT, SUCCESSOR_COUNT, graph); + setException(exception); + setBlockSuccessor(0, otherSuccessor); + setBlockSuccessor(1, catchSuccessor); + this.catchType = catchType; + } + + public RiType catchType() { + return catchType; + } + + /** + * Gets the block corresponding to the catch block. + * @return the true successor + */ + public Instruction catchSuccessor() { + return blockSuccessor(1); + } + + /** + * Gets the block corresponding to the rest of the dispatch chain. + * @return the false successor + */ + public Instruction otherSuccessor() { + return blockSuccessor(0); + } + + /** + * Gets the block corresponding to the specified outcome of the branch. + * @param istrue {@code true} if the true successor is requested, {@code false} otherwise + * @return the corresponding successor + */ + public Instruction successor(boolean istrue) { + return blockSuccessor(istrue ? 1 : 0); + } + + @Override + public void accept(ValueVisitor v) { + v.visitExceptionDispatch(this); + } + + @Override + public void print(LogStream out) { + out.print("exception_dispatch "). + print(exception()). + print(' '). + print("instanceof"). + print(' '). + print(catchType().name()). + print(" then "). + print(blockSuccessors().get(1).toString()). + print(" else B"). + print(blockSuccessors().get(0).toString()); + } + + @Override + public String shortName() { + return "Dispatch " + catchType().name(); + } + + @Override + public Node copy(Graph into) { + ExceptionDispatch x = new ExceptionDispatch(null, null, null, catchType, into); + return x; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/ExceptionEdgeInstruction.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/ExceptionEdgeInstruction.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.ir; + + +public interface ExceptionEdgeInstruction { + Instruction exceptionEdge(); +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/ExceptionObject.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/ExceptionObject.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.ir; + +import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.graph.*; +import com.sun.cri.ci.*; + +/** + * The {@code ExceptionObject} instruction represents the incoming exception object to an exception handler. + */ +public final class ExceptionObject extends Instruction { + + private static final int INPUT_COUNT = 0; + private static final int SUCCESSOR_COUNT = 0; + + /** + * Constructs a new ExceptionObject instruction. + * @param stateBefore TODO + * @param graph + */ + public ExceptionObject(Graph graph) { + super(CiKind.Object, INPUT_COUNT, SUCCESSOR_COUNT, graph); + } + + @Override + public void accept(ValueVisitor v) { + v.visitExceptionObject(this); + } + + @Override + public void print(LogStream out) { + out.print("incoming exception"); + } + + @Override + public Node copy(Graph into) { + ExceptionObject x = new ExceptionObject(into); + return x; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/FixedNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/FixedNode.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.ir; + +import com.oracle.max.graal.graph.*; +import com.sun.cri.ci.*; + + +public abstract class FixedNode extends Value { + + public FixedNode(CiKind kind, int inputCount, int successorCount, Graph graph) { + super(kind, inputCount, successorCount, graph); + } + +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/FloatingNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/FloatingNode.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.ir; + +import com.oracle.max.graal.graph.*; +import com.sun.cri.ci.*; + + +public abstract class FloatingNode extends Value { + + /** + * @param kind + * @param inputCount + * @param successorCount + * @param graph + */ + public FloatingNode(CiKind kind, int inputCount, int successorCount, Graph graph) { + super(kind, inputCount, successorCount, graph); + } + +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/If.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/If.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.ir; + +import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.graph.*; +import com.sun.cri.ci.*; + +/** + * The {@code If} instruction represents a branch that can go one of two directions + * depending on the outcome of a comparison. + */ +public final class If extends BlockEnd { + + private static final int INPUT_COUNT = 1; + private static final int INPUT_COMPARE = 0; + + private static final int SUCCESSOR_COUNT = 0; + + @Override + protected int inputCount() { + return super.inputCount() + INPUT_COUNT; + } + + @Override + protected int successorCount() { + return super.successorCount() + SUCCESSOR_COUNT; + } + + /** + * The instruction that produces the first input to this comparison. + */ + public Compare compare() { + return (Compare) inputs().get(super.inputCount() + INPUT_COMPARE); + } + + public Value setCompare(Compare n) { + return (Value) inputs().set(super.inputCount() + INPUT_COMPARE, n); + } + + public If(Compare compare, Graph graph) { + super(CiKind.Illegal, 2, INPUT_COUNT, SUCCESSOR_COUNT, graph); + setCompare(compare); + } + + /** + * Gets the block corresponding to the true successor. + * @return the true successor + */ + public Instruction trueSuccessor() { + return blockSuccessor(0); + } + + /** + * Gets the block corresponding to the false successor. + * @return the false successor + */ + public Instruction falseSuccessor() { + return blockSuccessor(1); + } + + /** + * Gets the block corresponding to the specified outcome of the branch. + * @param istrue {@code true} if the true successor is requested, {@code false} otherwise + * @return the corresponding successor + */ + public Instruction successor(boolean istrue) { + return blockSuccessor(istrue ? 0 : 1); + } + + @Override + public void accept(ValueVisitor v) { + v.visitIf(this); + } + + @Override + public void print(LogStream out) { + out.print("if "). + print(compare().x()). + print(' '). + print(compare().condition().operator). + print(' '). + print(compare().y()). + print(" then "). + print(blockSuccessors().get(0)). + print(" else "). + print(blockSuccessors().get(1)); + } + + @Override + public String shortName() { + return "If " + compare().condition.operator; + } + + @Override + public Node copy(Graph into) { + return new If(compare(), into); + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/InstanceOf.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/InstanceOf.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.ir; + +import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.compiler.util.*; +import com.oracle.max.graal.graph.*; +import com.sun.cri.bytecode.*; +import com.sun.cri.ci.*; +import com.sun.cri.ri.*; + +/** + * The {@code InstanceOf} instruction represents an instanceof test. + */ +public final class InstanceOf extends TypeCheck { + + private static final int INPUT_COUNT = 0; + private static final int SUCCESSOR_COUNT = 0; + + /** + * Constructs a new InstanceOf instruction. + * @param targetClass the target class of the instanceof check + * @param object the instruction producing the object input to this instruction + * @param graph + */ + public InstanceOf(RiType targetClass, Value targetClassInstruction, Value object, Graph graph) { + super(targetClass, targetClassInstruction, object, CiKind.Int, INPUT_COUNT, SUCCESSOR_COUNT, graph); + } + + @Override + public void accept(ValueVisitor v) { + v.visitInstanceOf(this); + } + + @Override + public int valueNumber() { + return Util.hash1(Bytecodes.INSTANCEOF, object()); + } + + @Override + public boolean valueEqual(Node i) { + if (i instanceof InstanceOf) { + InstanceOf o = (InstanceOf) i; + return targetClass == o.targetClass && object() == o.object(); + } + return false; + } + + @Override + public void print(LogStream out) { + out.print("instanceof(").print(object()).print(") ").print(CiUtil.toJavaName(targetClass())); + } + + @Override + public Node copy(Graph into) { + InstanceOf x = new InstanceOf(targetClass, null, null, into); + return x; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Instruction.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Instruction.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.ir; + +import java.util.*; + +import com.oracle.max.graal.compiler.*; +import com.oracle.max.graal.compiler.value.*; +import com.oracle.max.graal.graph.*; +import com.sun.cri.ci.*; + +/** + * Denotes an instruction node in the IR, which is a {@link Value} that + * can be added to a basic block (whereas other {@link Value} nodes such as {@link Phi} and + * {@link Local} cannot be added to basic blocks). + * + * Subclasses of instruction represent arithmetic and object operations, + * control flow operators, phi statements, method calls, the start of basic blocks, and + * the end of basic blocks. + * + * Instruction nodes are chained together in a basic block through the embedded + * {@link Instruction#next} field. An Instruction may also have a list of {@link ExceptionHandler}s. + */ +public abstract class Instruction extends FixedNode { + + private static final int INPUT_COUNT = 0; + + private static final int SUCCESSOR_COUNT = 1; + public static final int SUCCESSOR_NEXT = 0; + + @Override + protected int inputCount() { + return super.inputCount() + INPUT_COUNT; + } + + @Override + protected int successorCount() { + return super.successorCount() + SUCCESSOR_COUNT; + } + + /** + * Links to next instruction in a basic block, to {@code null} if this instruction is the end of a basic block or to + * itself if not in a block. + */ + public Instruction next() { + return (Instruction) successors().get(super.successorCount() + SUCCESSOR_NEXT); + } + + public Node setNext(Instruction next) { + return successors().set(super.successorCount() + SUCCESSOR_NEXT, next); + } + + public int nextIndex() { + return super.successorCount() + SUCCESSOR_NEXT; + } + + + public static final int SYNCHRONIZATION_ENTRY_BCI = -1; + + /** + * Constructs a new instruction with the specified value type. + * @param kind the value type for this instruction + * @param inputCount + * @param successorCount + */ + public Instruction(CiKind kind, int inputCount, int successorCount, Graph graph) { + super(kind, inputCount + INPUT_COUNT, successorCount + SUCCESSOR_COUNT, graph); + C1XMetrics.HIRInstructions++; + } + + + /** + * Gets the list of predecessors of this block. + * @return the predecessor list + */ + @SuppressWarnings({ "unchecked", "rawtypes" }) + public List blockPredecessors() { + return (List) Collections.unmodifiableList(predecessors()); + } + + /** + * Get the number of predecessors. + * @return the number of predecessors + */ + public int numberOfPreds() { + return predecessors().size(); + } + + public Instruction predAt(int j) { + return (Instruction) predecessors().get(j); + } + + /** + * Gets the state after the instruction, if it is recorded. + * @return the state after the instruction + */ + public FrameState stateAfter() { + return null; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Invoke.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Invoke.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.ir; + +import java.util.*; + +import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.compiler.util.*; +import com.oracle.max.graal.graph.*; +import com.sun.cri.bytecode.*; +import com.sun.cri.ci.*; +import com.sun.cri.ri.*; + +/** + * The {@code Invoke} instruction represents all kinds of method calls. + */ +public final class Invoke extends StateSplit implements ExceptionEdgeInstruction { + + private final int argumentCount; + + private static final int SUCCESSOR_COUNT = 1; + private static final int SUCCESSOR_EXCEPTION_EDGE = 0; + + @Override + protected int inputCount() { + return super.inputCount() + argumentCount; + } + + @Override + protected int successorCount() { + return super.successorCount() + SUCCESSOR_COUNT; + } + + /** + * The list of instructions that produce input for this instruction. + */ + public Value argument(int index) { + assert index >= 0 && index < argumentCount; + return (Value) inputs().get(super.inputCount() + index); + } + + public Value setArgument(int index, Value n) { + assert index >= 0 && index < argumentCount; + return (Value) inputs().set(super.inputCount() + index, n); + } + + public int argumentCount() { + return argumentCount; + } + + /** + * The entry to the exception dispatch chain for this invoke. + */ + @Override + public Instruction exceptionEdge() { + return (Instruction) successors().get(super.successorCount() + SUCCESSOR_EXCEPTION_EDGE); + } + + public Instruction setExceptionEdge(Instruction n) { + return (Instruction) successors().set(super.successorCount() + SUCCESSOR_EXCEPTION_EDGE, n); + } + + public final int opcode; + public final RiMethod target; + public final RiType returnType; + public final int bci; // XXX needed because we can not compute the bci from the sateBefore bci of this Invoke was optimized from INVOKEINTERFACE to INVOKESPECIAL + + /** + * Constructs a new Invoke instruction. + * + * @param opcode the opcode of the invoke + * @param result the result type + * @param args the list of instructions producing arguments to the invocation, including the receiver object + * @param isStatic {@code true} if this call is static (no receiver object) + * @param target the target method being called + * @param stateBefore the state before executing the invocation + */ + public Invoke(int bci, int opcode, CiKind result, Value[] args, RiMethod target, RiType returnType, Graph graph) { + super(result, args.length, SUCCESSOR_COUNT, graph); + this.opcode = opcode; + this.target = target; + this.returnType = returnType; + this.bci = bci; + + this.argumentCount = args.length; + for (int i = 0; i < args.length; i++) { + setArgument(i, args[i]); + } + } + + /** + * Gets the opcode of this invoke instruction. + * @return the opcode + */ + public int opcode() { + return opcode; + } + + /** + * Checks whether this is an invocation of a static method. + * @return {@code true} if the invocation is a static invocation + */ + public boolean isStatic() { + return opcode == Bytecodes.INVOKESTATIC; + } + + @Override + public RiType declaredType() { + return returnType; + } + + /** + * Gets the instruction that produces the receiver object for this invocation, if any. + * @return the instruction that produces the receiver object for this invocation if any, {@code null} if this + * invocation does not take a receiver object + */ + public Value receiver() { + assert !isStatic(); + return argument(0); + } + + /** + * Gets the target method for this invocation instruction. + * @return the target method + */ + public RiMethod target() { + return target; + } + + /** + * Checks whether this invocation has a receiver object. + * @return {@code true} if this invocation has a receiver object; {@code false} otherwise, if this is a + * static call + */ + public boolean hasReceiver() { + return !isStatic(); + } + + @Override + public void accept(ValueVisitor v) { + v.visitInvoke(this); + } + + public CiKind[] signature() { + CiKind receiver = isStatic() ? null : target.holder().kind(); + return Util.signatureToKinds(target.signature(), receiver); + } + + @Override + public void print(LogStream out) { + int argStart = 0; + if (hasReceiver()) { + out.print(receiver()).print('.'); + argStart = 1; + } + + RiMethod target = target(); + out.print(target.name()).print('('); + for (int i = argStart; i < argumentCount; i++) { + if (i > argStart) { + out.print(", "); + } + out.print(argument(i)); + } + out.print(CiUtil.format(") [method: %H.%n(%p):%r]", target, false)); + } + + @Override + public Map getDebugProperties() { + Map properties = super.getDebugProperties(); + properties.put("opcode", Bytecodes.nameOf(opcode)); + properties.put("target", CiUtil.format("%H.%n(%p):%r", target, false)); + properties.put("bci", bci); + return properties; + } + + @Override + public Node copy(Graph into) { + Invoke x = new Invoke(bci, opcode, kind, new Value[argumentCount], target, returnType, into); + return x; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/LeftShift.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/LeftShift.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.ir; + +import com.oracle.max.graal.graph.*; +import com.sun.cri.bytecode.*; +import com.sun.cri.ci.*; + + +public final class LeftShift extends Shift { + + /** + * @param opcode + * @param kind + * @param x + * @param y + * @param graph + */ + public LeftShift(CiKind kind, Value x, Value y, Graph graph) { + super(kind, kind == CiKind.Int ? Bytecodes.ISHL : Bytecodes.LSHL, x, y, graph); + } + + @Override + public String shortName() { + return "<<"; + } + + @Override + public Node copy(Graph into) { + LeftShift ls = new LeftShift(kind, null, null, graph()); + return ls; + } + +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/LoadField.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/LoadField.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.ir; + +import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.graph.*; +import com.sun.cri.ci.*; +import com.sun.cri.ri.*; + +/** + * The {@code LoadField} instruction represents a read of a static or instance field. + */ +public final class LoadField extends AccessField { + + private static final int INPUT_COUNT = 0; + private static final int SUCCESSOR_COUNT = 0; + + /** + * Creates a new LoadField instance. + * @param object the receiver object + * @param field the compiler interface field + * @param isStatic indicates if the field is static + * @param stateAfter the state after the field access + * @param graph + * @param isLoaded indicates if the class is loaded + */ + public LoadField(Value object, RiField field, Graph graph) { + super(field.kind().stackKind(), object, field, INPUT_COUNT, SUCCESSOR_COUNT, graph); + } + + /** + * Gets the declared type of the field being accessed. + * @return the declared type of the field being accessed. + */ + @Override + public RiType declaredType() { + return field().type(); + } + + /** + * Gets the exact type of the field being accessed. If the field type is + * a primitive array or an instance class and the class is loaded and final, + * then the exact type is the same as the declared type. Otherwise it is {@code null} + * @return the exact type of the field if known; {@code null} otherwise + */ + @Override + public RiType exactType() { + RiType declaredType = declaredType(); + return declaredType.isResolved() ? declaredType.exactType() : null; + } + + @Override + public void accept(ValueVisitor v) { + v.visitLoadField(this); + } + + @Override + public void print(LogStream out) { + out.print(object()). + print("."). + print(field.name()). + print(" [field: "). + print(CiUtil.format("%h.%n:%t", field, false)). + print("]"); + } + + @Override + public boolean needsStateAfter() { + return false; + } + + @Override + public Node copy(Graph into) { + LoadField x = new LoadField(null, field, into); + return x; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/LoadIndexed.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/LoadIndexed.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.ir; + +import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.graph.*; +import com.sun.cri.ci.*; +import com.sun.cri.ri.*; + +/** + * The {@code LoadIndexed} instruction represents a read from an element of an array. + */ +public final class LoadIndexed extends AccessIndexed { + + private static final int INPUT_COUNT = 0; + private static final int SUCCESSOR_COUNT = 0; + + /** + * Creates a new LoadIndexed instruction. + * @param array the instruction producing the array + * @param index the instruction producing the index + * @param length the instruction producing the length + * @param elementKind the element type + * @param graph + */ + public LoadIndexed(Value array, Value index, Value length, CiKind elementKind, Graph graph) { + super(elementKind.stackKind(), array, index, length, elementKind, INPUT_COUNT, SUCCESSOR_COUNT, graph); + } + + /** + * Gets the declared type of this instruction's result. + * @return the declared type + */ + @Override + public RiType declaredType() { + RiType arrayType = array().declaredType(); + if (arrayType == null) { + return null; + } + return arrayType.componentType(); + } + + /** + * Gets the exact type of this instruction's result. + * @return the exact type + */ + @Override + public RiType exactType() { + RiType declared = declaredType(); + return declared != null && declared.isResolved() ? declared.exactType() : null; + } + + @Override + public void accept(ValueVisitor v) { + v.visitLoadIndexed(this); + } + + @Override + public void print(LogStream out) { + out.print(array()).print('[').print(index()).print("] (").print(kind.typeChar).print(')'); + } + + @Override + public boolean needsStateAfter() { + return false; + } + + @Override + public Node copy(Graph into) { + LoadIndexed x = new LoadIndexed(null, null, null, elementKind(), into); + return x; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Local.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Local.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.ir; + +import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.graph.*; +import com.sun.cri.ci.*; +import com.sun.cri.ri.*; + +/** + * The {@code Local} instruction is a placeholder for an incoming argument + * to a function call. + */ +public final class Local extends FloatingNode { + + private static final int INPUT_COUNT = 1; + + private static final int SUCCESSOR_COUNT = 0; + + private final int index; + private RiType declaredType; + + public Local(CiKind kind, int javaIndex, Graph graph) { + super(kind, INPUT_COUNT, SUCCESSOR_COUNT, graph); + this.index = javaIndex; + } + + /** + * Gets the index of this local. + * @return the index + */ + public int index() { + return index; + } + + /** + * Sets the declared type of this local, e.g. derived from the signature of the method. + * @param declaredType the declared type of the local variable + */ + public void setDeclaredType(RiType declaredType) { + this.declaredType = declaredType; + } + + /** + * Computes the declared type of the result of this instruction, if possible. + * @return the declared type of the result of this instruction, if it is known; {@code null} otherwise + */ + @Override + public RiType declaredType() { + return declaredType; + } + + @Override + public void accept(ValueVisitor v) { + v.visitLocal(this); + } + + @Override + public void print(LogStream out) { + out.print("local[index ").print(index()).print(']'); + } + + @Override + protected int inputCount() { + return super.inputCount() + INPUT_COUNT; + } + + @Override + protected int successorCount() { + return super.successorCount() + SUCCESSOR_COUNT; + } + + @Override + public Node copy(Graph into) { + Local x = new Local(kind, index, into); + x.setDeclaredType(declaredType()); + return x; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Logic.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Logic.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.ir; + +import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.graph.*; +import com.sun.cri.ci.*; + +/** + * The {@code LogicOp} class definition. + */ +public abstract class Logic extends Binary { + + private static final int INPUT_COUNT = 0; + private static final int SUCCESSOR_COUNT = 0; + + /** + * Constructs a new logic operation instruction. + * @param opcode the opcode of the logic operation + * @param x the first input into this instruction + * @param y the second input into this instruction + */ + public Logic(CiKind kind, int opcode, Value x, Value y, Graph graph) { + super(kind, opcode, x, y, INPUT_COUNT, SUCCESSOR_COUNT, graph); + } + + @Override + public void accept(ValueVisitor v) { + v.visitLogic(this); + } + + @Override + public void print(LogStream out) { + out.print(x()).print(' ').print(this.shortName()).print(' ').print(y()); + } + + @Override + public abstract String shortName(); +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/LookupSwitch.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/LookupSwitch.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.ir; + +import static com.oracle.max.graal.compiler.debug.InstructionPrinter.InstructionLineColumn.*; + +import java.util.*; + +import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.graph.*; + +/** + * The {@code LookupSwitch} instruction represents a lookup switch bytecode, which has a sorted + * array of key values. + */ +public final class LookupSwitch extends Switch { + + private static final int INPUT_COUNT = 0; + private static final int SUCCESSOR_COUNT = 0; + + final int[] keys; + + /** + * Constructs a new LookupSwitch instruction. + * @param value the instruction producing the value being switched on + * @param successors the list of successors + * @param keys the list of keys, sorted + * @param stateAfter the state after the switch + * @param graph + */ + public LookupSwitch(Value value, List successors, int[] keys, Graph graph) { + super(value, successors, INPUT_COUNT, SUCCESSOR_COUNT, graph); + this.keys = keys; + } + + /** + * Gets the key at the specified index. + * @param i the index + * @return the key at that index + */ + public int keyAt(int i) { + return keys[i]; + } + + public int keysLength() { + return keys.length; + } + + @Override + public void accept(ValueVisitor v) { + v.visitLookupSwitch(this); + } + + @Override + public void print(LogStream out) { + out.print("lookupswitch "); + out.println(value()); + int l = numberOfCases(); + for (int i = 0; i < l; i++) { + INSTRUCTION.advance(out); + out.printf("case %5d: B%d%n", keyAt(i), blockSuccessors().get(i)); + } + INSTRUCTION.advance(out); + out.print("default : ").print(defaultSuccessor()); + } + + @Override + public Node copy(Graph into) { + LookupSwitch x = new LookupSwitch(null, Arrays.asList(new Instruction[numberOfCases() + 1]), keys.clone(), into); + return x; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/LoopBegin.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/LoopBegin.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.ir; + +import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.graph.*; + +public class LoopBegin extends Merge { + + private static final int INPUT_COUNT = 0; + private static final int SUCCESSOR_COUNT = 0; + + public LoopBegin(Graph graph) { + super(INPUT_COUNT, SUCCESSOR_COUNT, graph); + } + + public LoopEnd loopEnd() { + for (Node usage : usages()) { + if (usage instanceof LoopEnd) { + LoopEnd end = (LoopEnd) usage; + if (end.loopBegin() == this) { + return end; + } + } + } + assert false : "Begin should always have a LoopEnd"; + return null; + } + + @Override + public void accept(ValueVisitor v) { + v.visitLoopBegin(this); + } + + @Override + public void print(LogStream out) { + out.print("loopBegin"); + } + + @Override + public String shortName() { + return "LoopBegin"; + } + + @Override + public Node copy(Graph into) { + LoopBegin x = new LoopBegin(into); + return x; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/LoopEnd.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/LoopEnd.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.ir; + +import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.graph.*; + + +public class LoopEnd extends Merge { + + private static final int INPUT_COUNT = 1; + private static final int INPUT_LOOP_BEGIN = 0; + + private static final int SUCCESSOR_COUNT = 0; + + @Override + protected int inputCount() { + return super.inputCount() + INPUT_COUNT; + } + + @Override + protected int successorCount() { + return super.successorCount() + SUCCESSOR_COUNT; + } + + /** + * The instruction which produces the input value to this instruction. + */ + public LoopBegin loopBegin() { + return (LoopBegin) inputs().get(super.inputCount() + INPUT_LOOP_BEGIN); + } + + public LoopBegin setLoopBegin(LoopBegin n) { + return (LoopBegin) inputs().set(super.inputCount() + INPUT_LOOP_BEGIN, n); + } + + public LoopEnd(Graph graph) { + super(INPUT_COUNT, SUCCESSOR_COUNT, graph); + } + + @Override + public void accept(ValueVisitor v) { + v.visitLoopEnd(this); + } + + @Override + public void print(LogStream out) { + out.print("loopEnd ").print(loopBegin()); + } + + @Override + public String shortName() { + return "LoopEnd"; + } + + @Override + public Node copy(Graph into) { + LoopEnd x = new LoopEnd(into); + return x; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Merge.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Merge.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,282 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.ir; + +import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.compiler.util.*; +import com.oracle.max.graal.compiler.value.*; +import com.oracle.max.graal.graph.*; +import com.sun.cri.ci.*; + +/** + * Denotes the beginning of a basic block, and holds information + * about the basic block, including the successor and + * predecessor blocks, exception handlers, liveness information, etc. + */ +public class Merge extends StateSplit { + + private static final int INPUT_COUNT = 0; + + private static final int SUCCESSOR_COUNT = 0; + + @Override + protected int inputCount() { + return super.inputCount() + INPUT_COUNT; + } + + @Override + protected int successorCount() { + return super.successorCount() + SUCCESSOR_COUNT; + } + + @Override + public boolean needsStateAfter() { + return false; + } + + /** + * Constructs a new Merge at the specified bytecode index. + * @param bci the bytecode index of the start + * @param blockID the ID of the block + * @param graph + */ + public Merge(Graph graph) { + super(CiKind.Illegal, INPUT_COUNT, SUCCESSOR_COUNT, graph); + } + + protected Merge(int inputCount, int successorCount, Graph graph) { + super(CiKind.Illegal, inputCount + INPUT_COUNT, successorCount + SUCCESSOR_COUNT, graph); + } + + @Override + public void accept(ValueVisitor v) { + v.visitMerge(this); + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("merge #"); + builder.append(id()); + builder.append(" ["); + + builder.append("]"); + + builder.append(" -> "); + boolean hasSucc = false; + for (Node s : this.successors()) { + if (hasSucc) { + builder.append(", "); + } + builder.append("#"); + if (s != null) { + builder.append(s.id()); + } else { + builder.append("null"); + } + hasSucc = true; + } + + return builder.toString(); + } + + public void printWithoutPhis(LogStream out) { + // print block id + out.print("B").print(id()).print(" "); + + // print flags + StringBuilder sb = new StringBuilder(8); + if (sb.length() != 0) { + out.print('(').print(sb.toString()).print(')'); + } + + // print block bci range + out.print('[').print(-1).print(", ").print(-1).print(']'); + + // print block successors + //if (end != null && end.blockSuccessors().size() > 0) { + out.print(" ."); + for (Node successor : this.successors()) { + if (successor instanceof Value) { + out.print((Value) successor); + } else { + out.print(successor.toString()); + } + } + //} + + // print predecessors +// if (!blockPredecessors().isEmpty()) { +// out.print(" pred:"); +// for (Instruction pred : blockPredecessors()) { +// out.print(pred.block()); +// } +// } + } + + @Override + public void print(LogStream out) { + + printWithoutPhis(out); + + // print phi functions + boolean hasPhisInLocals = false; + boolean hasPhisOnStack = false; + + //if (end() != null && end().stateAfter() != null) { + FrameState state = stateBefore(); + + int i = 0; + while (!hasPhisOnStack && i < state.stackSize()) { + Value value = state.stackAt(i); + hasPhisOnStack = isPhiAtBlock(value); + if (value != null && !(value instanceof Phi && ((Phi) value).isDead())) { + i += value.kind.sizeInSlots(); + } else { + i++; + } + } + + for (i = 0; !hasPhisInLocals && i < state.localsSize();) { + Value value = state.localAt(i); + hasPhisInLocals = isPhiAtBlock(value); + // also ignore illegal HiWords + if (value != null && !(value instanceof Phi && ((Phi) value).isDead())) { + i += value.kind.sizeInSlots(); + } else { + i++; + } + } + //} + + // print values in locals + if (hasPhisInLocals) { + out.println(); + out.println("Locals:"); + + int j = 0; + while (j < state.localsSize()) { + Value value = state.localAt(j); + if (value != null) { + out.println(stateString(j, value)); + // also ignore illegal HiWords + if (value instanceof Phi && ((Phi) value).isDead()) { + j += 1; + } else { + j += value.kind.sizeInSlots(); + } + } else { + j++; + } + } + out.println(); + } + + // print values on stack + if (hasPhisOnStack) { + out.println(); + out.println("Stack:"); + int j = 0; + while (j < stateBefore().stackSize()) { + Value value = stateBefore().stackAt(j); + if (value != null) { + out.println(stateString(j, value)); + j += value.kind.sizeInSlots(); + } else { + j++; + } + } + } + + } + + /** + * Determines if a given instruction is a phi whose {@linkplain Phi#block() join block} is a given block. + * + * @param value the instruction to test + * @param block the block that may be the join block of {@code value} if {@code value} is a phi + * @return {@code true} if {@code value} is a phi and its join block is {@code block} + */ + private boolean isPhiAtBlock(Value value) { + return value instanceof Phi && ((Phi) value).block() == this; + } + + + /** + * Formats a given instruction as a value in a {@linkplain FrameState frame state}. If the instruction is a phi defined at a given + * block, its {@linkplain Phi#valueCount() inputs} are appended to the returned string. + * + * @param index the index of the value in the frame state + * @param value the frame state value + * @param block if {@code value} is a phi, then its inputs are formatted if {@code block} is its + * {@linkplain Phi#block() join point} + * @return the instruction representation as a string + */ + public String stateString(int index, Value value) { + StringBuilder sb = new StringBuilder(30); + sb.append(String.format("%2d %s", index, Util.valueString(value))); + if (value instanceof Phi) { + Phi phi = (Phi) value; + // print phi operands + if (phi.block() == this) { + sb.append(" ["); + for (int j = 0; j < phi.valueCount(); j++) { + sb.append(' '); + Value operand = phi.valueAt(j); + if (operand != null) { + sb.append(Util.valueString(operand)); + } else { + sb.append("NULL"); + } + } + sb.append("] "); + } + } + return sb.toString(); + } + + @Override + public String shortName() { + return "Merge #" + id(); + } + + @Override + public Node copy(Graph into) { + assert getClass() == Merge.class : "copy of " + getClass(); + Merge x = new Merge(into); + return x; + } + + public void removePhiPredecessor(Node pred) { + int predIndex = predecessors().lastIndexOf(pred); + assert predIndex != -1; + + for (Node usage : usages()) { + if (usage instanceof Phi) { + Phi phi = (Phi) usage; +// assert phi.valueCount() == predecessors().size(); + phi.removeInput(predIndex); + } + } + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/MonitorAddress.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/MonitorAddress.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.ir; + +import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.graph.*; +import com.sun.cri.ci.*; + +/** + * Instruction that is used to refer to the address of an on-stack monitor. + */ +public final class MonitorAddress extends Value { + + private static final int INPUT_COUNT = 0; + private static final int SUCCESSOR_COUNT = 0; + + private int monitor; + + public MonitorAddress(int monitor, Graph graph) { + super(CiKind.Word, INPUT_COUNT, SUCCESSOR_COUNT, graph); + this.monitor = monitor; + } + + @Override + public void accept(ValueVisitor v) { + v.visitMonitorAddress(this); + } + + public int monitor() { + return monitor; + } + + @Override + public void print(LogStream out) { + out.print("monitor_address (").print(monitor()).print(")"); + } + + @Override + public Node copy(Graph into) { + MonitorAddress x = new MonitorAddress(monitor, into); + return x; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/MonitorEnter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/MonitorEnter.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.ir; + +import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.graph.*; + +/** + * The {@code MonitorEnter} instruction represents the acquisition of a monitor. + */ +public final class MonitorEnter extends AccessMonitor { + + private static final int INPUT_COUNT = 0; + + private static final int SUCCESSOR_COUNT = 1; + + @Override + protected int successorCount() { + return super.successorCount() + SUCCESSOR_COUNT; + } + + /** + * Creates a new MonitorEnter instruction. + * + * @param object the instruction producing the object + * @param lockAddress the address of the on-stack lock object or {@code null} if the runtime does not place locks on the stack + * @param lockNumber the number of the lock + * @param graph + */ + public MonitorEnter(Value object, Value lockAddress, int lockNumber, Graph graph) { + super(object, lockAddress, lockNumber, INPUT_COUNT, SUCCESSOR_COUNT, graph); + } + + @Override + public void accept(ValueVisitor v) { + v.visitMonitorEnter(this); + } + + @Override + public void print(LogStream out) { + out.print("enter monitor[").print(lockNumber).print("](").print(object()).print(')'); + } + + @Override + public Node copy(Graph into) { + MonitorEnter x = new MonitorEnter(null, null, lockNumber, into); + return x; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/MonitorExit.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/MonitorExit.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.ir; + +import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.graph.*; + +/** + * The {@code MonitorExit} instruction represents a monitor release. + */ +public final class MonitorExit extends AccessMonitor { + + private static final int INPUT_COUNT = 0; + private static final int SUCCESSOR_COUNT = 0; + + /** + * Creates a new MonitorExit instruction. + * + * @param object the instruction produces the object value + * @param lockAddress the address of the on-stack lock object or {@code null} if the runtime does not place locks on the stack + * @param lockNumber the number of the lock + * @param graph + */ + public MonitorExit(Value object, Value lockAddress, int lockNumber, Graph graph) { + super(object, lockAddress, lockNumber, INPUT_COUNT, SUCCESSOR_COUNT, graph); + } + + @Override + public void accept(ValueVisitor v) { + v.visitMonitorExit(this); + } + + @Override + public void print(LogStream out) { + out.print("exit monitor[").print(lockNumber).print("](").print(object()).print(')'); + } + + @Override + public Node copy(Graph into) { + MonitorExit x = new MonitorExit(null, null, lockNumber, into); + return x; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Negate.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Negate.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.ir; + +import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.compiler.util.*; +import com.oracle.max.graal.graph.*; +import com.sun.cri.bytecode.*; +import com.sun.cri.ci.*; + +/** + * The {@code NegateOp} instruction negates its operand. + */ +public final class Negate extends FloatingNode { + + private static final int INPUT_COUNT = 2; + private static final int INPUT_X = 0; + private static final int INPUT_Y = 1; + + private static final int SUCCESSOR_COUNT = 0; + + @Override + protected int inputCount() { + return super.inputCount() + INPUT_COUNT; + } + + @Override + protected int successorCount() { + return super.successorCount() + SUCCESSOR_COUNT; + } + + /** + * The instruction producing input to this instruction. + */ + public Value x() { + return (Value) inputs().get(super.inputCount() + INPUT_X); + } + + public Value setX(Value n) { + return (Value) inputs().set(super.inputCount() + INPUT_X, n); + } + + /** + * Creates new NegateOp instance. + * @param x the instruction producing the value that is input to this instruction + */ + public Negate(Value x, Graph graph) { + super(x.kind, INPUT_COUNT, SUCCESSOR_COUNT, graph); + setX(x); + } + + // for copying + private Negate(CiKind kind, Graph graph) { + super(kind, INPUT_COUNT, SUCCESSOR_COUNT, graph); + } + + @Override + public void accept(ValueVisitor v) { + v.visitNegate(this); + } + + @Override + public int valueNumber() { + return Util.hash1(Bytecodes.INEG, x()); + } + + @Override + public boolean valueEqual(Node i) { + if (i instanceof Negate) { + Negate o = (Negate) i; + return x() == o.x(); + } + return false; + } + + @Override + public void print(LogStream out) { + out.print("- ").print(x()); + } + + @Override + public Node copy(Graph into) { + Negate x = new Negate(kind, into); + return x; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewArray.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewArray.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.ir; + +import com.oracle.max.graal.graph.*; +import com.sun.cri.ci.*; + +/** + * The {@code NewArray} class is the base of all instructions that allocate arrays. + */ +public abstract class NewArray extends Instruction { + + private static final int INPUT_COUNT = 1; + private static final int INPUT_LENGTH = 0; + + private static final int SUCCESSOR_COUNT = 0; + + @Override + protected int inputCount() { + return super.inputCount() + INPUT_COUNT; + } + + @Override + protected int successorCount() { + return super.successorCount() + SUCCESSOR_COUNT; + } + + /** + * The instruction that produces the length of this array. + */ + public Value length() { + return (Value) inputs().get(super.inputCount() + INPUT_LENGTH); + } + + public Value setLength(Value n) { + return (Value) inputs().set(super.inputCount() + INPUT_LENGTH, n); + } + + /** + * Constructs a new NewArray instruction. + * @param length the instruction that produces the length for this allocation + * @param stateBefore the state before the allocation + * @param inputCount + * @param successorCount + * @param graph + */ + NewArray(Value length, int inputCount, int successorCount, Graph graph) { + super(CiKind.Object, inputCount + INPUT_COUNT, successorCount + SUCCESSOR_COUNT, graph); + setLength(length); + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewInstance.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewInstance.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.ir; + +import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.graph.*; +import com.sun.cri.ci.*; +import com.sun.cri.ri.*; + +/** + * The {@code NewInstance} instruction represents the allocation of an instance class object. + */ +public final class NewInstance extends FloatingNode { + + private static final int INPUT_COUNT = 0; + private static final int SUCCESSOR_COUNT = 0; + + final RiType instanceClass; + public final int cpi; + public final RiConstantPool constantPool; + + /** + * Constructs a NewInstance instruction. + * @param type the class being allocated + * @param cpi the constant pool index + * @param stateBefore the state before executing this instruction + * @param graph + */ + public NewInstance(RiType type, int cpi, RiConstantPool constantPool, Graph graph) { + super(CiKind.Object, INPUT_COUNT, SUCCESSOR_COUNT, graph); + this.instanceClass = type; + this.cpi = cpi; + this.constantPool = constantPool; + } + + /** + * Gets the instance class being allocated by this instruction. + * @return the instance class allocated + */ + public RiType instanceClass() { + return instanceClass; + } + + /** + * Gets the exact type produced by this instruction. For allocations of instance classes, this is + * always the class allocated. + * @return the exact type produced by this instruction + */ + @Override + public RiType exactType() { + return instanceClass; + } + + @Override + public void accept(ValueVisitor v) { + v.visitNewInstance(this); + } + + @Override + public void print(LogStream out) { + out.print("new instance ").print(CiUtil.toJavaName(instanceClass())); + } + + @Override + public Node copy(Graph into) { + NewInstance x = new NewInstance(instanceClass, cpi, constantPool, into); + return x; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewMultiArray.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewMultiArray.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.ir; + +import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.graph.*; +import com.sun.cri.ci.*; +import com.sun.cri.ri.*; + +/** + * The {@code NewMultiArray} instruction represents an allocation of a multi-dimensional object + * array. + */ +public final class NewMultiArray extends NewArray { + + private final int dimensionCount; + + private static final int SUCCESSOR_COUNT = 0; + + @Override + protected int inputCount() { + return super.inputCount() + dimensionCount; + } + + @Override + protected int successorCount() { + return super.successorCount() + SUCCESSOR_COUNT; + } + + /** + * The list of instructions which produce input for this instruction. + */ + public Value dimension(int index) { + assert index >= 0 && index < dimensionCount; + return (Value) inputs().get(super.inputCount() + index); + } + + public Value setDimension(int index, Value n) { + assert index >= 0 && index < dimensionCount; + return (Value) inputs().set(super.inputCount() + index, n); + } + + /** + * The rank of the array allocated by this instruction, i.e. how many array dimensions. + */ + public int dimensionCount() { + return dimensionCount; + } + + public final RiType elementType; + public final int cpi; + public final RiConstantPool constantPool; + + /** + * Constructs a new NewMultiArray instruction. + * @param elementType the element type of the array + * @param dimensions the instructions which produce the dimensions for this array + * @param stateBefore the state before this instruction + * @param cpi the constant pool index for resolution + * @param riConstantPool the constant pool for resolution + * @param graph + */ + public NewMultiArray(RiType elementType, Value[] dimensions, int cpi, RiConstantPool riConstantPool, Graph graph) { + super(null, dimensions.length, SUCCESSOR_COUNT, graph); + this.constantPool = riConstantPool; + this.elementType = elementType; + this.cpi = cpi; + + this.dimensionCount = dimensions.length; + for (int i = 0; i < dimensions.length; i++) { + setDimension(i, dimensions[i]); + } + } + + @Override + public void accept(ValueVisitor v) { + v.visitNewMultiArray(this); + } + + /** + * Gets the element type of the array. + * @return the element type of the array + */ + public RiType elementType() { + return elementType; + } + + @Override + public void print(LogStream out) { + out.print("new multi array ["); + for (int i = 0; i < dimensionCount; i++) { + if (i > 0) { + out.print(", "); + } + out.print(dimension(i)); + } + out.print("] ").print(CiUtil.toJavaName(elementType)); + } + + @Override + public Node copy(Graph into) { + NewMultiArray x = new NewMultiArray(elementType, new Value[dimensionCount], cpi, constantPool, into); + return x; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewObjectArray.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewObjectArray.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.ir; + +import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.graph.*; +import com.sun.cri.ci.*; +import com.sun.cri.ri.*; + +/** + * The {@code NewObjectArray} instruction represents an allocation of an object array. + */ +public final class NewObjectArray extends NewArray { + + private static final int INPUT_COUNT = 0; + private static final int SUCCESSOR_COUNT = 0; + + final RiType elementClass; + + /** + * Constructs a new NewObjectArray instruction. + * @param elementClass the class of elements in this array + * @param length the instruction producing the length of the array + * @param graph + */ + public NewObjectArray(RiType elementClass, Value length, Graph graph) { + super(length, INPUT_COUNT, SUCCESSOR_COUNT, graph); + this.elementClass = elementClass; + } + + /** + * Gets the type of the elements of the array. + * @return the element type of the array + */ + public RiType elementClass() { + return elementClass; + } + + @Override + public RiType exactType() { + return elementClass.arrayOf(); + } + + @Override + public RiType declaredType() { + return exactType(); + } + + @Override + public void accept(ValueVisitor v) { + v.visitNewObjectArray(this); + } + + @Override + public void print(LogStream out) { + out.print("new object array [").print(length()).print("] ").print(CiUtil.toJavaName(elementClass())); + } + + @Override + public Node copy(Graph into) { + NewObjectArray x = new NewObjectArray(elementClass, null, into); + return x; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewTypeArray.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewTypeArray.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.ir; + +import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.graph.*; +import com.sun.cri.ci.*; +import com.sun.cri.ri.*; + +/** + * The {@code NewTypeArray} class definition. + */ +public final class NewTypeArray extends NewArray { + + private static final int INPUT_COUNT = 0; + private static final int SUCCESSOR_COUNT = 0; + + final RiType elementType; + + public NewTypeArray(Value length, RiType elementType, Graph graph) { + super(length, INPUT_COUNT, SUCCESSOR_COUNT, graph); + this.elementType = elementType; + } + + public CiKind elementKind() { + return elementType.kind(); + } + + @Override + public RiType declaredType() { + return elementType.arrayOf(); + } + + @Override + public RiType exactType() { + return elementType.arrayOf(); + } + + @Override + public void accept(ValueVisitor v) { + v.visitNewTypeArray(this); + } + + @Override + public void print(LogStream out) { + out.print("new ").print(elementKind().name()).print(" array [").print(length()).print(']'); + } + + @Override + public Node copy(Graph into) { + NewTypeArray x = new NewTypeArray(null, elementType, into); + return x; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NormalizeCompare.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NormalizeCompare.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.ir; + +import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.graph.*; +import com.sun.cri.bytecode.*; +import com.sun.cri.ci.*; + +/** + * Returns -1, 0, or 1 if either x > y, x == y, or x < y. + */ +public final class NormalizeCompare extends Binary { + + private static final int INPUT_COUNT = 0; + private static final int SUCCESSOR_COUNT = 0; + + /** + * Creates a new compare operation. + * @param opcode the bytecode opcode + * @param kind the result kind + * @param x the first input + * @param y the second input + */ + public NormalizeCompare(int opcode, CiKind kind, Value x, Value y, Graph graph) { + super(kind, opcode, x, y, INPUT_COUNT, SUCCESSOR_COUNT, graph); + } + + @Override + public void accept(ValueVisitor v) { + v.visitMaterialize(this); + } + + @Override + public void print(LogStream out) { + out.print(x()). + print(' '). + print(Bytecodes.operator(opcode)). + print(' '). + print(y()); + } + + @Override + public Node copy(Graph into) { + return new NormalizeCompare(opcode, kind, null, null, into); + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NullCheck.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NullCheck.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.ir; + +import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.compiler.util.*; +import com.oracle.max.graal.graph.*; +import com.sun.cri.bytecode.*; +import com.sun.cri.ci.*; +import com.sun.cri.ri.*; + +/** + * The {@code NullCheck} class represents an explicit null check instruction. + */ +public final class NullCheck extends Instruction { + + private static final int INPUT_COUNT = 1; + private static final int INPUT_OBJECT = 0; + + private static final int SUCCESSOR_COUNT = 0; + + @Override + protected int inputCount() { + return super.inputCount() + INPUT_COUNT; + } + + @Override + protected int successorCount() { + return super.successorCount() + SUCCESSOR_COUNT; + } + + /** + * The instruction that produces the object tested against null. + */ + public Value object() { + return (Value) inputs().get(super.inputCount() + INPUT_OBJECT); + } + + public Value setObject(Value n) { + return (Value) inputs().set(super.inputCount() + INPUT_OBJECT, n); + } + + /** + * Constructs a new NullCheck instruction. + * @param object the instruction producing the object to check against null + * @param stateBefore the state before executing the null check + * @param graph + */ + public NullCheck(Value object, Graph graph) { + super(object.kind, INPUT_COUNT, SUCCESSOR_COUNT, graph); + setObject(object); + } + + // for copying + private NullCheck(CiKind kind, Graph graph) { + super(kind, INPUT_COUNT, SUCCESSOR_COUNT, graph); + } + + @Override + public void accept(ValueVisitor v) { + v.visitNullCheck(this); + } + + @Override + public int valueNumber() { + return Util.hash1(Bytecodes.IFNONNULL, object()); + } + + @Override + public boolean valueEqual(Node i) { + if (i instanceof NullCheck) { + NullCheck o = (NullCheck) i; + return object() == o.object(); + } + return false; + } + + @Override + public RiType declaredType() { + // null check does not alter the type of the object + return object().declaredType(); + } + + @Override + public RiType exactType() { + // null check does not alter the type of the object + return object().exactType(); + } + + @Override + public void print(LogStream out) { + out.print("null_check(").print(object()).print(')'); + } + + @Override + public Node copy(Graph into) { + NullCheck x = new NullCheck(kind, into); + return x; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Or.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Or.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.ir; + +import com.oracle.max.graal.compiler.opt.CanonicalizerPhase.*; +import com.oracle.max.graal.graph.*; +import com.sun.cri.bytecode.*; +import com.sun.cri.ci.*; + + +/** + * + */ +public final class Or extends Logic { + private static final OrCanonicalizerOp CANONICALIZER = new OrCanonicalizerOp(); + + /** + * @param opcode + * @param kind + * @param x + * @param y + * @param graph + */ + public Or(CiKind kind, Value x, Value y, Graph graph) { + super(kind, kind == CiKind.Int ? Bytecodes.IOR : Bytecodes.LOR, x, y, graph); + } + + @Override + public String shortName() { + return "|"; + } + + @Override + public Node copy(Graph into) { + Or x = new Or(kind, null, null, into); + return x; + } + + @SuppressWarnings("unchecked") + @Override + public T lookup(Class clazz) { + if (clazz == CanonicalizerOp.class) { + return (T) CANONICALIZER; + } + return super.lookup(clazz); + } + + private static class OrCanonicalizerOp implements CanonicalizerOp { + @Override + public Node canonical(Node node) { + assert node instanceof Or; + Or or = (Or) node; + CiKind kind = or.kind; + Graph graph = or.graph(); + Value x = or.x(); + Value y = or.y(); + if (x == y) { + return x; + } + if (x.isConstant() && !y.isConstant()) { + or.swapOperands(); + Value t = y; + y = x; + x = t; + } + if (x.isConstant()) { + if (kind == CiKind.Int) { + return Constant.forInt(x.asConstant().asInt() | y.asConstant().asInt(), graph); + } else { + assert kind == CiKind.Long; + return Constant.forLong(x.asConstant().asLong() | y.asConstant().asLong(), graph); + } + } else if (y.isConstant()) { + if (kind == CiKind.Int) { + int c = y.asConstant().asInt(); + if (c == -1) { + return Constant.forInt(-1, graph); + } + if (c == 0) { + return x; + } + } else { + assert kind == CiKind.Long; + long c = y.asConstant().asLong(); + if (c == -1) { + return Constant.forLong(-1, graph); + } + if (c == 0) { + return x; + } + } + } + return or; + } + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Phi.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Phi.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.ir; + +import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.graph.*; +import com.sun.cri.ci.*; + +/** + * The {@code Phi} instruction represents the merging of dataflow + * in the instruction graph. It refers to a join block and a variable. + */ +public final class Phi extends FixedNode { + + private static final int DEFAULT_MAX_VALUES = 2; + + private static final int INPUT_COUNT = 1; + private static final int INPUT_BLOCK = 0; + + private final int maxValues; + + private static final int SUCCESSOR_COUNT = 0; + + private int usedInputCount; + private boolean isDead; + + @Override + protected int inputCount() { + return super.inputCount() + INPUT_COUNT + maxValues; + } + + @Override + protected int successorCount() { + return super.successorCount() + SUCCESSOR_COUNT; + } + + /** + * The join block for this phi. + */ + public Merge block() { + return (Merge) inputs().get(super.inputCount() + INPUT_BLOCK); + } + + public Value setBlock(Value n) { + return (Merge) inputs().set(super.inputCount() + INPUT_BLOCK, n); + } + + /** + * Create a new Phi for the specified join block and local variable (or operand stack) slot. + * @param kind the type of the variable + * @param block the join point + * @param graph + */ + public Phi(CiKind kind, Merge block, Graph graph) { + this(kind, block, DEFAULT_MAX_VALUES, graph); + } + + public Phi(CiKind kind, Merge block, int maxValues, Graph graph) { + super(kind, INPUT_COUNT + maxValues, SUCCESSOR_COUNT, graph); + this.maxValues = maxValues; + usedInputCount = 0; + setBlock(block); + } + + /** + * Get the instruction that produces the value associated with the i'th predecessor + * of the join block. + * @param i the index of the predecessor + * @return the instruction that produced the value in the i'th predecessor + */ + public Value valueAt(int i) { + return (Value) inputs().get(INPUT_COUNT + i); + } + + public Node setValueAt(int i, Node x) { + return inputs().set(INPUT_COUNT + i, x); + } + + /** + * Get the number of inputs to this phi (i.e. the number of predecessors to the join block). + * @return the number of inputs in this phi + */ + public int valueCount() { + return usedInputCount; + } + + @Override + public void accept(ValueVisitor v) { + v.visitPhi(this); + } + + /** + * Make this phi illegal if types were not merged correctly. + */ + public void makeDead() { + isDead = true; + } + + public boolean isDead() { + return isDead; + } + + @Override + public void print(LogStream out) { + out.print("phi function ("); + for (int i = 0; i < valueCount(); ++i) { + if (i != 0) { + out.print(' '); + } + out.print(valueAt(i)); + } + out.print(')'); + } + + @Override + public String shortName() { + StringBuilder str = new StringBuilder(); + for (int i = 0; i < valueCount(); ++i) { + if (i != 0) { + str.append(' '); + } + str.append(valueAt(i) == null ? "-" : valueAt(i).id()); + } + return "Phi: (" + str + ")"; + } + + public Phi addInput(Node y) { + assert !this.isDeleted() && !y.isDeleted(); + Phi phi = this; + if (usedInputCount == maxValues) { + phi = new Phi(kind, block(), maxValues * 2, graph()); + for (int i = 0; i < valueCount(); ++i) { + phi.addInput(valueAt(i)); + } + phi.addInput(y); + this.replace(phi); + } else { + setValueAt(usedInputCount++, y); + } + return phi; + } + + public void removeInput(int index) { + assert index < valueCount() : "index: " + index + ", valueCount: " + valueCount() + "@phi " + id(); + setValueAt(index, Node.Null); + for (int i = index + 1; i < valueCount(); ++i) { + setValueAt(i - 1, valueAt(i)); + } + usedInputCount--; + } + + @Override + public Node copy(Graph into) { + Phi x = new Phi(kind, null, maxValues, into); + x.usedInputCount = usedInputCount; + x.isDead = isDead; + return x; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Placeholder.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Placeholder.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.ir; + +import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.graph.*; +import com.sun.cri.ci.*; + + +public class Placeholder extends StateSplit { + + private static final int INPUT_COUNT = 0; + + private static final int SUCCESSOR_COUNT = 0; + + @Override + protected int inputCount() { + return super.inputCount() + INPUT_COUNT; + } + + @Override + protected int successorCount() { + return super.successorCount() + SUCCESSOR_COUNT; + } + + public Placeholder(Graph graph) { + super(CiKind.Void, INPUT_COUNT, SUCCESSOR_COUNT, graph); + } + + @Override + public void accept(ValueVisitor v) { + assert false; + } + + @Override + public void print(LogStream out) { + assert false; + } + + @Override + public String shortName() { + return "Placeholder" + id(); + } + + @Override + public Node copy(Graph into) { + Placeholder x = new Placeholder(into); + return x; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/RegisterFinalizer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/RegisterFinalizer.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.ir; + +import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.compiler.value.*; +import com.oracle.max.graal.graph.*; +import com.sun.cri.ci.*; + +/** + * This instruction is used to perform the finalizer registration at the end of the java.lang.Object constructor. + */ +public class RegisterFinalizer extends StateSplit { + + private static final int INPUT_COUNT = 1; + private static final int INPUT_OBJECT = 0; + + private static final int SUCCESSOR_COUNT = 0; + + @Override + protected int inputCount() { + return super.inputCount() + INPUT_COUNT; + } + + @Override + protected int successorCount() { + return super.successorCount() + SUCCESSOR_COUNT; + } + + /** + * The instruction that produces the object whose finalizer should be registered. + */ + public Value object() { + return (Value) inputs().get(super.inputCount() + INPUT_OBJECT); + } + + public Value setObject(Value n) { + return (Value) inputs().set(super.inputCount() + INPUT_OBJECT, n); + } + + public RegisterFinalizer(Value object, FrameState stateBefore, Graph graph) { + super(CiKind.Void, INPUT_COUNT, SUCCESSOR_COUNT, graph); + setObject(object); + setStateBefore(stateBefore); + } + + @Override + public void accept(ValueVisitor v) { + v.visitRegisterFinalizer(this); + } + + @Override + public void print(LogStream out) { + out.print("register finalizer ").print(object()); + } + + @Override + public Node copy(Graph into) { + RegisterFinalizer x = new RegisterFinalizer(null, null, into); + return x; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Return.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Return.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.ir; + +import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.graph.*; +import com.sun.cri.ci.*; + +/** + * The {@code Return} class definition. + */ +public final class Return extends BlockEnd { + + private static final int INPUT_COUNT = 1; + private static final int INPUT_RESULT = 0; + + private static final int SUCCESSOR_COUNT = 1; + private static final int SUCCESSOR_END = 0; + + @Override + protected int inputCount() { + return super.inputCount() + INPUT_COUNT; + } + + @Override + protected int successorCount() { + return super.successorCount() + SUCCESSOR_COUNT; + } + + /** + * The instruction that produces the result for the return. + */ + public Value result() { + return (Value) inputs().get(super.inputCount() + INPUT_RESULT); + } + + public Value setResult(Value n) { + return (Value) inputs().set(super.inputCount() + INPUT_RESULT, n); + } + + @Override + public Instruction next() { + return null; + } + + /** + * Constructs a new Return instruction. + * @param result the instruction producing the result for this return; {@code null} if this + * is a void return + * @param graph + */ + public Return(Value result, Graph graph) { + super(result == null ? CiKind.Void : result.kind, 0, INPUT_COUNT, SUCCESSOR_COUNT, graph); + setResult(result); + } + + // for copying + private Return(CiKind kind, Graph graph) { + super(kind, 0, INPUT_COUNT, SUCCESSOR_COUNT, graph); + } + + @Override + public void accept(ValueVisitor v) { + v.visitReturn(this); + } + + @Override + public void print(LogStream out) { + if (result() == null) { + out.print("return"); + } else { + out.print(kind.typeChar).print("return ").print(result()); + } + } + + @Override + public Node copy(Graph into) { + Return x = new Return(kind, into); + return x; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/RightShift.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/RightShift.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.ir; + +import com.oracle.max.graal.graph.*; +import com.sun.cri.bytecode.*; +import com.sun.cri.ci.*; + + +public final class RightShift extends Shift { + + /** + * @param opcode + * @param kind + * @param x + * @param y + * @param graph + */ + public RightShift(CiKind kind, Value x, Value y, Graph graph) { + super(kind, kind == CiKind.Int ? Bytecodes.ISHR : Bytecodes.LSHR, x, y, graph); + } + + @Override + public String shortName() { + return ">>"; + } + + @Override + public Node copy(Graph into) { + RightShift rs = new RightShift(kind, null, null, graph()); + return rs; + } + +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Shift.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Shift.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.ir; + +import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.graph.*; +import com.sun.cri.ci.*; + +/** + * The {@code ShiftOp} class represents shift operations. + */ +public abstract class Shift extends Binary { + + private static final int INPUT_COUNT = 0; + private static final int SUCCESSOR_COUNT = 0; + + /** + * Creates a new shift operation. + * @param opcode the opcode of the shift + * @param x the first input value + * @param y the second input value + */ + public Shift(CiKind kind, int opcode, Value x, Value y, Graph graph) { + super(kind, opcode, x, y, INPUT_COUNT, SUCCESSOR_COUNT, graph); + } + + @Override + public void accept(ValueVisitor v) { + v.visitShift(this); + } + + @Override + public void print(LogStream out) { + out.print(x()).print(' ').print(this.shortName()).print(' ').print(y()); + } + + @Override + public abstract String shortName(); +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/StateSplit.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/StateSplit.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.ir; + +import com.oracle.max.graal.compiler.value.*; +import com.oracle.max.graal.graph.*; +import com.sun.cri.ci.*; + +/** + * The {@code StateSplit} class is the abstract base class of all instructions + * that store an immutable copy of the frame state. + */ +public abstract class StateSplit extends Instruction { + + private static final int INPUT_COUNT = 1; + private static final int INPUT_STATE_BEFORE = 0; + + private static final int SUCCESSOR_COUNT = 1; + private static final int SUCCESSOR_STATE_AFTER = 0; + + @Override + protected int inputCount() { + return super.inputCount() + INPUT_COUNT; + } + + @Override + protected int successorCount() { + return super.successorCount() + SUCCESSOR_COUNT; + } + + /** + * The state for this instruction. + */ + public FrameState stateBefore() { + return (FrameState) inputs().get(super.inputCount() + INPUT_STATE_BEFORE); + } + + public FrameState setStateBefore(FrameState n) { + FrameState oldState = stateBefore(); + try { + return (FrameState) inputs().set(super.inputCount() + INPUT_STATE_BEFORE, n); + } finally { + if (oldState != n && oldState != null) { + oldState.delete(); + } + } + } + + /** + * The state for this instruction. + */ + @Override + public FrameState stateAfter() { + return (FrameState) successors().get(super.successorCount() + SUCCESSOR_STATE_AFTER); + } + + public FrameState setStateAfter(FrameState n) { + return (FrameState) successors().set(super.successorCount() + SUCCESSOR_STATE_AFTER, n); + } + + /** + * Creates a new state split with the specified value type. + * @param kind the type of the value that this instruction produces + * @param inputCount + * @param successorCount + * @param graph + */ + public StateSplit(CiKind kind, int inputCount, int successorCount, Graph graph) { + super(kind, inputCount + INPUT_COUNT, successorCount + SUCCESSOR_COUNT, graph); + } + + public boolean needsStateAfter() { + return true; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/StoreField.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/StoreField.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.ir; + +import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.graph.*; +import com.sun.cri.ci.*; +import com.sun.cri.ri.*; + +/** + * The {@code StoreField} instruction represents a write to a static or instance field. + */ +public final class StoreField extends AccessField { + + private static final int INPUT_COUNT = 1; + private static final int INPUT_VALUE = 0; + + private static final int SUCCESSOR_COUNT = 0; + + @Override + protected int inputCount() { + return super.inputCount() + INPUT_COUNT; + } + + @Override + protected int successorCount() { + return super.successorCount() + SUCCESSOR_COUNT; + } + + /** + * The value that is written to the field. + */ + public Value value() { + return (Value) inputs().get(super.inputCount() + INPUT_VALUE); + } + + public Value setValue(Value n) { + return (Value) inputs().set(super.inputCount() + INPUT_VALUE, n); + } + + /** + * Creates a new LoadField instance. + * @param object the receiver object + * @param field the compiler interface field + * @param value the instruction representing the value to store to the field + * @param stateAfter the state after the field access + * @param graph + */ + public StoreField(Value object, RiField field, Value value, Graph graph) { + super(CiKind.Void, object, field, INPUT_COUNT, SUCCESSOR_COUNT, graph); + setValue(value); + } + + @Override + public void accept(ValueVisitor v) { + v.visitStoreField(this); + } + + @Override + public void print(LogStream out) { + out.print(object()). + print("."). + print(field().name()). + print(" := "). + print(value()). + print(" [type: ").print(CiUtil.format("%h.%n:%t", field(), false)). + print(']'); + } + + @Override + public Node copy(Graph into) { + StoreField x = new StoreField(null, field, null, into); + return x; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/StoreIndexed.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/StoreIndexed.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.ir; + +import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.graph.*; +import com.sun.cri.ci.*; + +/** + * The {@code StoreIndexed} instruction represents a write to an array element. + */ +public final class StoreIndexed extends AccessIndexed { + + private static final int INPUT_COUNT = 1; + private static final int INPUT_VALUE = 0; + + private static final int SUCCESSOR_COUNT = 0; + + @Override + protected int inputCount() { + return super.inputCount() + INPUT_COUNT; + } + + @Override + protected int successorCount() { + return super.successorCount() + SUCCESSOR_COUNT; + } + + /** + * The instruction that produces the value that is to be stored into the array. + */ + public Value value() { + return (Value) inputs().get(super.inputCount() + INPUT_VALUE); + } + + public Value setValue(Value n) { + return (Value) inputs().set(super.inputCount() + INPUT_VALUE, n); + } + + /** + * Creates a new StoreIndexed instruction. + * @param array the instruction producing the array + * @param index the instruction producing the index + * @param length the instruction producing the length + * @param elementKind the element type + * @param value the value to store into the array + * @param stateAfter the state after executing this instruction + * @param graph + */ + public StoreIndexed(Value array, Value index, Value length, CiKind elementKind, Value value, Graph graph) { + super(CiKind.Void, array, index, length, elementKind, INPUT_COUNT, SUCCESSOR_COUNT, graph); + setValue(value); + } + + @Override + public void accept(ValueVisitor v) { + v.visitStoreIndexed(this); + } + + @Override + public void print(LogStream out) { + out.print(array()).print('[').print(index()).print("] := ").print(value()).print(" (").print(kind.typeChar).print(')'); + } + + @Override + public Node copy(Graph into) { + StoreIndexed x = new StoreIndexed(null, null, null, elementKind(), null, into); + return x; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Switch.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Switch.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.ir; + +import java.util.*; + +import com.oracle.max.graal.graph.*; +import com.sun.cri.ci.*; + +/** + * The {@code Switch} class is the base of both lookup and table switches. + */ +public abstract class Switch extends BlockEnd { + + private static final int INPUT_COUNT = 1; + private static final int INPUT_VALUE = 0; + + private static final int SUCCESSOR_COUNT = 0; + + @Override + protected int inputCount() { + return super.inputCount() + INPUT_COUNT; + } + + @Override + protected int successorCount() { + return super.successorCount() + SUCCESSOR_COUNT; + } + + /** + * The instruction that provides the input value to this switch. + */ + public Value value() { + return (Value) inputs().get(super.inputCount() + INPUT_VALUE); + } + + public Value setValue(Value n) { + return (Value) inputs().set(super.inputCount() + INPUT_VALUE, n); + } + + /** + * Constructs a new Switch. + * @param value the instruction that provides the value to be switched over + * @param successors the list of successors of this switch + * @param stateAfter the state after the switch + * @param graph + */ + public Switch(Value value, List successors, int inputCount, int successorCount, Graph graph) { + super(CiKind.Illegal, successors, inputCount + INPUT_COUNT, successorCount + SUCCESSOR_COUNT, graph); + setValue(value); + } + + /** + * Gets the number of cases that this switch covers (excluding the default case). + * @return the number of cases + */ + public int numberOfCases() { + return blockSuccessorCount() - 1; + } + +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/TableSwitch.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/TableSwitch.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.ir; + +import static com.oracle.max.graal.compiler.debug.InstructionPrinter.InstructionLineColumn.*; + +import java.util.*; + +import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.graph.*; + +/** + * The {@code TableSwitch} instruction represents a table switch. + */ +public final class TableSwitch extends Switch { + + private static final int INPUT_COUNT = 0; + private static final int SUCCESSOR_COUNT = 0; + + final int lowKey; + + /** + * Constructs a new TableSwitch instruction. + * @param value the instruction producing the value being switched on + * @param successors the list of successors + * @param lowKey the lowest integer key in the table + * @param stateAfter the state after the switch + * @param graph + */ + public TableSwitch(Value value, List successors, int lowKey, Graph graph) { + super(value, successors, INPUT_COUNT, SUCCESSOR_COUNT, graph); + this.lowKey = lowKey; + } + + /** + * Gets the lowest key in the table switch (inclusive). + * @return the low key + */ + public int lowKey() { + return lowKey; + } + + /** + * Gets the highest key in the table switch (exclusive). + * @return the high key + */ + public int highKey() { + return lowKey + numberOfCases(); + } + + @Override + public void accept(ValueVisitor v) { + v.visitTableSwitch(this); + } + + @Override + public void print(LogStream out) { + out.print("tableswitch "); + out.println(value()); + int l = numberOfCases(); + for (int i = 0; i < l; i++) { + INSTRUCTION.advance(out); + out.printf("case %5d: B%d%n", lowKey() + i, blockSuccessors().get(i)); + } + INSTRUCTION.advance(out); + out.print("default : ").print(defaultSuccessor()); + } + + @Override + public Node copy(Graph into) { + TableSwitch x = new TableSwitch(null, Arrays.asList(new Instruction[numberOfCases() + 1]), lowKey, into); + return x; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/TypeCheck.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/TypeCheck.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.ir; + +import com.oracle.max.graal.graph.*; +import com.sun.cri.ci.*; +import com.sun.cri.ri.*; + +/** + * The {@code TypeCheck} instruction is the base class of casts and instanceof tests. + */ +public abstract class TypeCheck extends FloatingNode { + + private static final int INPUT_COUNT = 2; + private static final int INPUT_OBJECT = 0; + private static final int INPUT_TARGET_CLASS_INSTRUCTION = 1; + + private static final int SUCCESSOR_COUNT = 0; + + @Override + protected int inputCount() { + return super.inputCount() + INPUT_COUNT; + } + + @Override + protected int successorCount() { + return super.successorCount() + SUCCESSOR_COUNT; + } + + /** + * The instruction which produces the object input. + */ + public Value object() { + return (Value) inputs().get(super.inputCount() + INPUT_OBJECT); + } + + public Value setObject(Value n) { + return (Value) inputs().set(super.inputCount() + INPUT_OBJECT, n); + } + + /** + * The instruction that loads the target class object that is used by this checkcast. + */ + public Value targetClassInstruction() { + return (Value) inputs().get(super.inputCount() + INPUT_TARGET_CLASS_INSTRUCTION); + } + + public Value setTargetClassInstruction(Value n) { + return (Value) inputs().set(super.inputCount() + INPUT_TARGET_CLASS_INSTRUCTION, n); + } + + final RiType targetClass; + + /** + * Creates a new TypeCheck instruction. + * @param targetClass the class which is being casted to or checked against + * @param object the instruction which produces the object + * @param kind the result type of this instruction + * @param stateBefore the state before this instruction is executed + * @param inputCount + * @param successorCount + * @param graph + */ + public TypeCheck(RiType targetClass, Value targetClassInstruction, Value object, CiKind kind, int inputCount, int successorCount, Graph graph) { + super(kind, inputCount + INPUT_COUNT, successorCount + SUCCESSOR_COUNT, graph); + this.targetClass = targetClass; + setObject(object); + setTargetClassInstruction(targetClassInstruction); + } + + /** + * Gets the target class, i.e. the class being cast to, or the class being tested against. + * @return the target class + */ + public RiType targetClass() { + return targetClass; + } + + /** + * Checks whether the target class of this instruction is loaded. + * @return {@code true} if the target class is loaded + */ + public boolean isLoaded() { + return targetClass != null; + } + +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/UnsignedRightShift.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/UnsignedRightShift.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.ir; + +import com.oracle.max.graal.graph.*; +import com.sun.cri.bytecode.*; +import com.sun.cri.ci.*; + + +public final class UnsignedRightShift extends Shift { + + /** + * @param opcode + * @param kind + * @param x + * @param y + * @param graph + */ + public UnsignedRightShift(CiKind kind, Value x, Value y, Graph graph) { + super(kind, kind == CiKind.Int ? Bytecodes.IUSHR : Bytecodes.LUSHR, x, y, graph); + } + + @Override + public String shortName() { + return ">>>"; + } + + @Override + public Node copy(Graph into) { + UnsignedRightShift x = new UnsignedRightShift(kind, null, null, graph()); + return x; + } + +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Unwind.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Unwind.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.ir; + +import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.graph.*; +import com.sun.cri.ci.*; + +/** + * Unwind takes an exception object, destroys the current stack frame and passes the exception object to the system's exception dispatch code. + */ +public final class Unwind extends BlockEnd { + + private static final int INPUT_COUNT = 1; + private static final int INPUT_EXCEPTION = 0; + + private static final int SUCCESSOR_COUNT = 0; + + @Override + protected int inputCount() { + return super.inputCount() + INPUT_COUNT; + } + + @Override + protected int successorCount() { + return super.successorCount() + SUCCESSOR_COUNT; + } + + @Override + public Instruction next() { + return null; + } + + /** + * The instruction that produces the exception object. + */ + public Value exception() { + return (Value) inputs().get(super.inputCount() + INPUT_EXCEPTION); + } + + public Value setException(Value n) { + assert n == null || n.kind == CiKind.Object; + return (Value) inputs().set(super.inputCount() + INPUT_EXCEPTION, n); + } + + public Unwind(Value exception, Graph graph) { + super(CiKind.Object, 0, INPUT_COUNT, SUCCESSOR_COUNT, graph); + setException(exception); + } + + @Override + public void accept(ValueVisitor v) { + v.visitUnwind(this); + } + + @Override + public void print(LogStream out) { + out.print(kind.typeChar).print("unwind ").print(exception()); + } + + @Override + public Node copy(Graph into) { + Unwind x = new Unwind(null, into); + return x; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Value.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Value.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,210 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.ir; + +import java.util.*; + +import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.graph.*; +import com.sun.cri.ci.*; +import com.sun.cri.ri.*; + +/** + * This class represents a value within the HIR graph, including local variables, phis, and + * all other instructions. + */ +public abstract class Value extends Node { + + /** + * The kind of this value. This is {@link CiKind#Void} for instructions that produce no value. + * This kind is guaranteed to be a {@linkplain CiKind#stackKind() stack kind}. + */ + public final CiKind kind; + + protected CiValue operand = CiValue.IllegalValue; + + /** + * Creates a new value with the specified kind. + * @param kind the type of this value + * @param inputCount + * @param successorCount + * @param graph + */ + public Value(CiKind kind, int inputCount, int successorCount, Graph graph) { + super(inputCount, successorCount, graph); + assert kind == kind.stackKind() : kind + " != " + kind.stackKind(); + this.kind = kind; + } + + /////////////// + // TODO: remove when Value class changes are completed + + @Override + protected Object clone() throws CloneNotSupportedException { + throw new CloneNotSupportedException(); + } + + /** + * Checks whether this value is a constant (i.e. it is of type {@link Constant}. + * @return {@code true} if this value is a constant + */ + public final boolean isConstant() { + return this instanceof Constant; + } + + /** + * Checks whether this value represents the null constant. + * @return {@code true} if this value represents the null constant + */ + public final boolean isNullConstant() { + return this instanceof Constant && ((Constant) this).value.isNull(); + } + + /** + * Convert this value to a constant if it is a constant, otherwise return null. + * @return the {@link CiConstant} represented by this value if it is a constant; {@code null} + * otherwise + */ + public final CiConstant asConstant() { + if (this instanceof Constant) { + return ((Constant) this).value; + } + return null; + } + + /** + * Gets the LIR operand associated with this instruction. + * @return the LIR operand for this instruction + */ + public final CiValue operand() { + return operand; + } + + /** + * Sets the LIR operand associated with this instruction. + * @param operand the operand to associate with this instruction + */ + public final void setOperand(CiValue operand) { + assert this.operand.isIllegal() : "operand cannot be set twice"; + assert operand != null && operand.isLegal() : "operand must be legal"; + assert operand.kind.stackKind() == this.kind; + this.operand = operand; + } + + /** + * Clears the LIR operand associated with this instruction. + */ + public final void clearOperand() { + this.operand = CiValue.IllegalValue; + } + + /** + * Computes the exact type of the result of this instruction, if possible. + * @return the exact type of the result of this instruction, if it is known; {@code null} otherwise + */ + public RiType exactType() { + return null; // default: unknown exact type + } + + /** + * Computes the declared type of the result of this instruction, if possible. + * @return the declared type of the result of this instruction, if it is known; {@code null} otherwise + */ + public RiType declaredType() { + return null; // default: unknown declared type + } + + /** + * Apply the specified closure to all the input values of this instruction. + * @param closure the closure to apply + */ + public void inputValuesDo(ValueClosure closure) { + for (int i = 0; i < inputs().size(); i++) { + inputs().set(i, closure.apply((Value) inputs().get(i))); + } + for (int i = 0; i < successors().size(); i++) { + successors().set(i, closure.apply((Value) successors().get(i))); + } + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("#"); + builder.append(id()); + builder.append(' '); + if (id() < 10) { + builder.append(' '); + } + builder.append(getClass().getSimpleName()); + builder.append(" [").append(flagsToString()).append("]"); + return builder.toString(); + } + + public String flagsToString() { + StringBuilder sb = new StringBuilder(); + return sb.toString(); + } + + /** + * Compute the value number of this Instruction. Local and global value numbering + * optimizations use a hash map, and the value number provides a hash code. + * If the instruction cannot be value numbered, then this method should return + * {@code 0}. + * @return the hashcode of this instruction + */ + public int valueNumber() { + return 0; + } + + /** + * Checks that this instruction is equal to another instruction for the purposes + * of value numbering. + * @param i the other instruction + * @return {@code true} if this instruction is equivalent to the specified + * instruction w.r.t. value numbering + */ + public boolean valueEqual(Node i) { + return false; + } + + /** + * This method supports the visitor pattern by accepting a visitor and calling the + * appropriate {@code visit()} method. + * + * @param v the visitor to accept + */ + public abstract void accept(ValueVisitor v); + + public abstract void print(LogStream out); + + @Override + public Map getDebugProperties() { + Map properties = super.getDebugProperties(); + properties.put("kind", kind.toString()); + properties.put("operand", operand == null ? "null" : operand.toString()); + return properties; + } + + +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/ValueAnchor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/ValueAnchor.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.ir; + +import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.graph.*; +import com.sun.cri.ci.*; + +/** + * The ValueAnchor instruction keeps non-CFG nodes above a certain point in the graph. + */ +public final class ValueAnchor extends Instruction { + + private static final int INPUT_COUNT = 1; + private static final int INPUT_OBJECT = 0; + + private static final int SUCCESSOR_COUNT = 0; + + @Override + protected int inputCount() { + return super.inputCount() + INPUT_COUNT; + } + + @Override + protected int successorCount() { + return super.successorCount() + SUCCESSOR_COUNT; + } + + /** + * The instruction that should be scheduled before this anchor. + */ + public Value object() { + return (Value) inputs().get(super.inputCount() + INPUT_OBJECT); + } + + public Value setObject(Value n) { + return (Value) inputs().set(super.inputCount() + INPUT_OBJECT, n); + } + + /** + * Constructs a new Anchor instruction. + * @param succ the successor block of the anchor + * @param graph + */ + public ValueAnchor(Value object, Graph graph) { + super(CiKind.Illegal, INPUT_COUNT, SUCCESSOR_COUNT, graph); + setObject(object); + } + + @Override + public void accept(ValueVisitor v) { + v.visitValueAnchor(this); + } + + @Override + public void print(LogStream out) { + out.print("value_anchor ").print(object()); + } + + @Override + public Node copy(Graph into) { + ValueAnchor x = new ValueAnchor(null, into); + return x; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/ValueClosure.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/ValueClosure.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.ir; + +/** + * The {@code ValueClosure} interface represents a first-class + * function that can be applied to a value. + */ +public interface ValueClosure { + Value apply(Value i); +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/ValueVisitor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/ValueVisitor.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.ir; + +import com.oracle.max.graal.compiler.value.*; + +/** + * The {@link ValueVisitor} implements one half of the visitor + * pattern for {@linkplain Value IR values}, allowing clients to implement functionality + * depending on the type of an value without doing type tests. + */ +public abstract class ValueVisitor { + // Checkstyle: stop + public abstract void visitArithmetic(Arithmetic i); + public abstract void visitArrayLength(ArrayLength i); + public abstract void visitMerge(Merge i); + public abstract void visitCheckCast(CheckCast i); + public abstract void visitMaterialize(NormalizeCompare i); + public abstract void visitConstant(Constant i); + public abstract void visitConvert(Convert i); + public abstract void visitExceptionObject(ExceptionObject i); + public abstract void visitFrameState(FrameState i); + public abstract void visitAnchor(Anchor i); + public abstract void visitIf(If i); + public abstract void visitIfOp(Conditional i); + public abstract void visitInstanceOf(InstanceOf i); + public abstract void visitInvoke(Invoke i); + public abstract void visitLoadField(LoadField i); + public abstract void visitLoadIndexed(LoadIndexed i); + public abstract void visitLocal(Local i); + public abstract void visitLogic(Logic i); + public abstract void visitLookupSwitch(LookupSwitch i); + public abstract void visitMonitorAddress(MonitorAddress monitorAddress); + public abstract void visitMonitorEnter(MonitorEnter i); + public abstract void visitMonitorExit(MonitorExit i); + public abstract void visitNegate(Negate i); + public abstract void visitNewInstance(NewInstance i); + public abstract void visitNewMultiArray(NewMultiArray i); + public abstract void visitNewObjectArray(NewObjectArray i); + public abstract void visitNewTypeArray(NewTypeArray i); + public abstract void visitNullCheck(NullCheck i); + public abstract void visitPhi(Phi i); + public abstract void visitRegisterFinalizer(RegisterFinalizer i); + public abstract void visitReturn(Return i); + public abstract void visitShift(Shift i); + public abstract void visitStoreField(StoreField i); + public abstract void visitStoreIndexed(StoreIndexed i); + public abstract void visitTableSwitch(TableSwitch i); + public abstract void visitDeoptimize(Deoptimize deoptimize); + public abstract void visitExceptionDispatch(ExceptionDispatch exceptionDispatch); + public abstract void visitUnwind(Unwind unwind); + public abstract void visitLoopBegin(LoopBegin loopBegin); + public abstract void visitLoopEnd(LoopEnd loopEnd); + public abstract void visitValueAnchor(ValueAnchor valueAnchor); +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Xor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Xor.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.ir; + +import com.oracle.max.graal.compiler.opt.CanonicalizerPhase.*; +import com.oracle.max.graal.graph.*; +import com.sun.cri.bytecode.*; +import com.sun.cri.ci.*; + +public final class Xor extends Logic { + private static final XorCanonicalizerOp CANONICALIZER = new XorCanonicalizerOp(); + + /** + * @param opcode + * @param kind + * @param x + * @param y + * @param graph + */ + public Xor(CiKind kind, Value x, Value y, Graph graph) { + super(kind, kind == CiKind.Int ? Bytecodes.IXOR : Bytecodes.LXOR, x, y, graph); + } + + @Override + public String shortName() { + return "^"; + } + + @Override + public Node copy(Graph into) { + Xor x = new Xor(kind, null, null, into); + return x; + } + + @SuppressWarnings("unchecked") + @Override + public T lookup(Class clazz) { + if (clazz == CanonicalizerOp.class) { + return (T) CANONICALIZER; + } + return super.lookup(clazz); + } + + private static class XorCanonicalizerOp implements CanonicalizerOp { + @Override + public Node canonical(Node node) { + assert node instanceof Xor; + Xor xor = (Xor) node; + CiKind kind = xor.kind; + Graph graph = xor.graph(); + Value x = xor.x(); + Value y = xor.y(); + if (x == y) { + if (kind == CiKind.Int) { + return Constant.forInt(0, graph); + } else { + assert kind == CiKind.Long; + return Constant.forLong(0L, graph); + } + } + if (x.isConstant() && !y.isConstant()) { + xor.swapOperands(); + Value t = y; + y = x; + x = t; + } + if (x.isConstant()) { + if (kind == CiKind.Int) { + return Constant.forInt(x.asConstant().asInt() ^ y.asConstant().asInt(), graph); + } else { + assert kind == CiKind.Long; + return Constant.forLong(x.asConstant().asLong() ^ y.asConstant().asLong(), graph); + } + } else if (y.isConstant()) { + if (kind == CiKind.Int) { + int c = y.asConstant().asInt(); + if (c == 0) { + return x; + } + } else { + assert kind == CiKind.Long; + long c = y.asConstant().asLong(); + if (c == 0) { + return x; + } + } + } + return xor; + } + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/package-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/package-info.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2010, 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * High-level intermediate representation (HIR). + */ +package com.oracle.max.graal.compiler.ir; diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/FrameMap.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/FrameMap.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,395 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.lir; + +import static com.sun.cri.ci.CiCallingConvention.Type.*; +import static com.sun.cri.ci.CiKind.*; +import static java.lang.reflect.Modifier.*; + +import com.oracle.max.graal.compiler.*; +import com.oracle.max.graal.compiler.globalstub.*; +import com.oracle.max.graal.compiler.util.*; +import com.sun.cri.bytecode.*; +import com.sun.cri.ci.*; +import com.sun.cri.ci.CiCallingConvention.*; +import com.sun.cri.ri.*; +import com.sun.cri.util.*; + +/** + * This class is used to build the stack frame layout for a compiled method. + * + * This is the format of a stack frame on an x86 (i.e. IA32 or X64) platform: + *

+ *   Base       Contents
+ *
+ *          :                                :
+ *          | incoming overflow argument n   |
+ *          |     ...                        |
+ *          | incoming overflow argument 0   |
+ *          | return address                 | Caller frame
+ *   -------+--------------------------------+----------------  ---
+ *          |                                |                   ^
+ *          : callee save area               :                   |
+ *          |                                |                   |
+ *          +--------------------------------+                   |
+ *          | alignment padding              |                   |
+ *          +--------------------------------+                   |
+ *          | ALLOCA block n                 |                   |
+ *          :     ...                        :                   |
+ *          | ALLOCA block 0                 | Current frame     |
+ *          +--------------------------------+                   |
+ *          | monitor n                      |                   |
+ *          :     ...                        :                   |
+ *          | monitor 0                      |                   |
+ *          +--------------------------------+    ---            |
+ *          | spill slot n                   |     ^           frame
+ *          :     ...                        :     |           size
+ *          | spill slot 0                   |  shared           |
+ *          +- - - - - - - - - - - - - - - - +   slot            |
+ *          | outgoing overflow argument n   |  indexes          |
+ *          |     ...                        |     |             |
+ *    %sp   | outgoing overflow argument 0   |     v             v
+ *   -------+--------------------------------+----------------  ---
+ *
+ * 
+ * Note that the size {@link Bytecodes#ALLOCA ALLOCA} blocks and {@code monitor}s in the frame may be greater + * than the size of a {@linkplain CiTarget#spillSlotSize spill slot}. + * + * @author Thomas Wuerthinger + * @author Ben L. Titzer + * @author Doug Simon + */ +public final class FrameMap { + + private final C1XCompilation compilation; + private final CiCallingConvention incomingArguments; + + /** + * Number of monitors used in this frame. + */ + private final int monitorCount; + + /** + * The final frame size. + * Value is only set after register allocation is complete. + */ + private int frameSize; + + /** + * The number of spill slots allocated by the register allocator. + * The value {@code -2} means that the size of outgoing argument stack slots + * is not yet fixed. The value {@code -1} means that the register + * allocator has started allocating spill slots and so the size of + * outgoing stack slots cannot change as outgoing stack slots and + * spill slots share the same slot index address space. + */ + private int spillSlotCount; + + /** + * The amount of memory allocated within the frame for uses of {@link Bytecodes#ALLOCA}. + */ + private int stackBlocksSize; + + /** + * Area occupied by outgoing overflow arguments. + * This value is adjusted as calling conventions for outgoing calls are retrieved. + */ + private int outgoingSize; + + /** + * Creates a new frame map for the specified method. + * + * @param compilation the compilation context + * @param method the outermost method being compiled + * @param monitors the number of monitors allocated on the stack for this method + */ + public FrameMap(C1XCompilation compilation, RiMethod method, int monitors) { + this.compilation = compilation; + this.frameSize = -1; + this.spillSlotCount = -2; + + assert monitors >= 0 : "not set"; + monitorCount = monitors; + if (method == null) { + incomingArguments = new CiCallingConvention(new CiValue[0], 0); + } else { + CiKind receiver = !isStatic(method.accessFlags()) ? method.holder().kind() : null; + incomingArguments = getCallingConvention(CRIUtil.signatureToKinds(method.signature(), receiver), JavaCallee); + } + } + + /** + * Gets the calling convention for a call with the specified signature. + * + * @param type the type of calling convention being requested + * @param signature the signature of the arguments + * @return a {@link CiCallingConvention} instance describing the location of parameters and the return value + */ + public CiCallingConvention getCallingConvention(CiKind[] signature, Type type) { + CiCallingConvention cc = compilation.registerConfig.getCallingConvention(type, signature, compilation.target); + if (type == RuntimeCall) { + assert cc.stackSize == 0 : "runtime call should not have stack arguments"; + } else if (type.out) { + assert frameSize == -1 : "frame size must not yet be fixed!"; + reserveOutgoing(cc.stackSize); + } + return cc; + } + + /** + * Gets the calling convention for the incoming arguments to the compiled method. + * @return the calling convention for incoming arguments + */ + public CiCallingConvention incomingArguments() { + return incomingArguments; + } + + /** + * Gets the frame size of the compiled frame. + * @return the size in bytes of the frame + */ + public int frameSize() { + assert this.frameSize != -1 : "frame size not computed yet"; + return frameSize; + } + + /** + * Sets the frame size for this frame. + * @param frameSize the frame size in bytes + */ + public void setFrameSize(int frameSize) { + assert this.frameSize == -1 : "should only be calculated once"; + this.frameSize = frameSize; + } + + /** + * Computes the frame size for this frame, given the number of spill slots. + * @param spillSlotCount the number of spill slots + */ + public void finalizeFrame(int spillSlotCount) { + assert this.spillSlotCount == -1 : "can only be set once"; + assert this.frameSize == -1 : "should only be calculated once"; + assert spillSlotCount >= 0 : "must be positive"; + + this.spillSlotCount = spillSlotCount; + int frameSize = offsetToStackBlocksEnd(); + frameSize += compilation.registerConfig.getCalleeSaveArea().size; + this.frameSize = compilation.target.alignFrameSize(frameSize); + } + + /** + * Informs the frame map that the compiled code uses a particular global stub, which + * may need stack space for outgoing arguments. + * + * @param stub the global stub + */ + public void usesGlobalStub(GlobalStub stub) { + reserveOutgoing(stub.argsSize); + } + + /** + * Converts a stack slot into a stack address. + * + * @param slot a stack slot + * @return a stack address + */ + public CiAddress toStackAddress(CiStackSlot slot) { + int size = compilation.target.sizeInBytes(slot.kind); + if (slot.inCallerFrame()) { + int offset = slot.index() * compilation.target.spillSlotSize + frameSize() + 8; + return new CiAddress(slot.kind, CiRegister.Frame.asValue(), offset); + } else { + int offset = offsetForOutgoingOrSpillSlot(slot.index(), size); + return new CiAddress(slot.kind, CiRegister.Frame.asValue(), offset); + } + } + + /** + * Gets the stack address within this frame for a given reserved stack block. + * + * @param stackBlock the value returned from {@link #reserveStackBlock(int)} identifying the stack block + * @return a representation of the stack location + */ + public CiAddress toStackAddress(StackBlock stackBlock) { + return new CiAddress(CiKind.Word, compilation.registerConfig.getFrameRegister().asValue(Word), offsetForStackBlock(stackBlock)); + } + + /** + * Converts the monitor index into the stack address of the object reference in the on-stack monitor. + * + * @param monitorIndex the monitor index + * @return a representation of the stack address + */ + public CiStackSlot toMonitorObjectStackAddress(int monitorIndex) { + int byteIndex = offsetForMonitorObject(monitorIndex); + assert byteIndex % compilation.target.wordSize == 0; + return CiStackSlot.get(CiKind.Object, byteIndex / compilation.target.wordSize); + } + + /** + * Converts the monitor index into the stack address of the on-stak monitor. + * + * @param monitorIndex the monitor index + * @return a representation of the stack address + */ + public CiStackSlot toMonitorBaseStackAddress(int monitorIndex) { + int byteIndex = offsetForMonitorBase(monitorIndex); + assert byteIndex % compilation.target.wordSize == 0; + return CiStackSlot.get(CiKind.Object, byteIndex / compilation.target.wordSize); + } + + /** + * Reserves space for stack-based outgoing arguments. + * + * @param argsSize the amount of space to reserve for stack-based outgoing arguments + */ + public void reserveOutgoing(int argsSize) { + assert spillSlotCount == -2 : "cannot reserve outgoing stack slot space once register allocation has started"; + if (argsSize > outgoingSize) { + outgoingSize = Util.roundUp(argsSize, compilation.target.spillSlotSize); + } + } + + /** + * Encapsulates the details of a stack block reserved by a call to {@link FrameMap#reserveStackBlock(int)}. + */ + public static final class StackBlock { + /** + * The size of this stack block. + */ + public final int size; + + /** + * The offset of this stack block within the frame space reserved for stack blocks. + */ + public final int offset; + + public StackBlock(int size, int offset) { + this.size = size; + this.offset = offset; + } + } + + /** + * Reserves a block of memory in the frame of the method being compiled. + * + * @param size the number of bytes to reserve + * @return a descriptor of the reserved block that can be used with {@link #toStackAddress(StackBlock)} once register + * allocation is complete and the size of the frame has been {@linkplain #finalizeFrame(int) finalized}. + */ + public StackBlock reserveStackBlock(int size) { + int wordSize = compilation.target.sizeInBytes(CiKind.Word); + assert (size % wordSize) == 0; + StackBlock block = new StackBlock(size, stackBlocksSize); + stackBlocksSize += size; + return block; + } + + private int offsetForStackBlock(StackBlock stackBlock) { + assert stackBlock.offset >= 0 && stackBlock.offset + stackBlock.size <= stackBlocksSize : "invalid stack block"; + int offset = offsetToStackBlocks() + stackBlock.offset; + assert offset <= (frameSize() - stackBlock.size) : "spill outside of frame"; + return offset; + } + + /** + * Gets the stack pointer offset for a outgoing stack argument or compiler spill slot. + * + * @param slotIndex the index of the stack slot within the slot index space reserved for + * @param size + * @return + */ + private int offsetForOutgoingOrSpillSlot(int slotIndex, int size) { + assert slotIndex >= 0 && slotIndex < (initialSpillSlot() + spillSlotCount) : "invalid spill slot"; + int offset = slotIndex * compilation.target.spillSlotSize; + assert offset <= (frameSize() - size) : "slot outside of frame"; + return offset; + } + + private int offsetForMonitorBase(int index) { + assert index >= 0 && index < monitorCount : "invalid monitor index : " + index + " (monitorCount=" + monitorCount + ")"; + int size = compilation.runtime.sizeOfBasicObjectLock(); + assert size != 0 : "monitors are not on the stack in this VM"; + int offset = offsetToMonitors() + index * size; + assert offset <= (frameSize() - size) : "monitor outside of frame"; + return offset; + } + + private int offsetToSpillArea() { + return outgoingSize; + } + + private int offsetToSpillEnd() { + return offsetToSpillArea() + spillSlotCount * compilation.target.spillSlotSize; + } + + private int offsetToMonitors() { + return offsetToCustomArea() + customAreaSize(); + } + + public int customAreaSize() { + return compilation.runtime.getCustomStackAreaSize(); + } + + public int offsetToCustomArea() { + return offsetToSpillEnd(); + } + + private int offsetToMonitorsEnd() { + return offsetToMonitors() + (monitorCount * compilation.runtime.sizeOfBasicObjectLock()); + } + + private int offsetToStackBlocks() { + return offsetToMonitorsEnd(); + } + + private int offsetToStackBlocksEnd() { + return offsetToStackBlocks() + stackBlocksSize; + } + + public int offsetToCalleeSaveAreaStart() { + return offsetToCalleeSaveAreaEnd() - compilation.registerConfig.getCalleeSaveArea().size; + } + + public int offsetToCalleeSaveAreaEnd() { + return frameSize; + } + + private int offsetForMonitorObject(int index) { + return offsetForMonitorBase(index) + compilation.runtime.basicObjectLockOffsetInBytes(); + } + + /** + * Gets the index of the first available spill slot relative to the base of the frame. + * After this call, no further outgoing stack slots can be {@linkplain #reserveOutgoing(int) reserved}. + * + * @return the index of the first available spill slot + */ + public int initialSpillSlot() { + if (spillSlotCount == -2) { + spillSlotCount = -1; + } + return outgoingSize / compilation.target.spillSlotSize; + } + +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRAssembler.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRAssembler.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,470 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.lir; + +import java.util.*; + +import com.oracle.max.asm.*; +import com.oracle.max.graal.compiler.*; +import com.oracle.max.graal.compiler.asm.*; +import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.compiler.gen.*; +import com.oracle.max.graal.compiler.ir.*; +import com.oracle.max.graal.compiler.lir.FrameMap.*; +import com.oracle.max.graal.compiler.util.*; +import com.sun.cri.ci.*; +import com.sun.cri.ci.CiTargetMethod.*; +import com.sun.cri.ri.*; +import com.sun.cri.xir.CiXirAssembler.*; + +/** + * The {@code LIRAssembler} class definition. + */ +public abstract class LIRAssembler { + + public final C1XCompilation compilation; + public final TargetMethodAssembler tasm; + public final AbstractAssembler asm; + public final FrameMap frameMap; + public int registerRestoreEpilogueOffset = -1; + + protected final List xirSlowPath; + protected final List branchTargetBlocks; + + private int lastDecodeStart; + + protected static class SlowPath { + public final LIRXirInstruction instruction; + public final Label[] labels; + public final Map marks; + + public SlowPath(LIRXirInstruction instruction, Label[] labels, Map marks) { + this.instruction = instruction; + this.labels = labels; + this.marks = marks; + } + } + + public LIRAssembler(C1XCompilation compilation) { + this.compilation = compilation; + this.tasm = compilation.assembler(); + this.asm = tasm.asm; + this.frameMap = compilation.frameMap(); + this.branchTargetBlocks = new ArrayList(); + this.xirSlowPath = new ArrayList(); + } + + protected RiMethod method() { + return compilation.method; + } + + protected void addSlowPath(SlowPath sp) { + xirSlowPath.add(sp); + } + + public void emitLocalStubs() { + for (SlowPath sp : xirSlowPath) { + emitSlowPath(sp); + } + + // No more code may be emitted after this point + } + + protected int codePos() { + return asm.codeBuffer.position(); + } + + public abstract void emitTraps(); + + public void emitCode(List hir) { + if (C1XOptions.PrintLIR && !TTY.isSuppressed()) { + LIRList.printLIR(hir); + } + + for (LIRBlock b : hir) { + emitBlock(b); + } + + assert checkNoUnboundLabels(); + } + + void emitBlock(LIRBlock block) { + + block.setBlockEntryPco(codePos()); + + if (C1XOptions.PrintLIRWithAssembly) { + block.printWithoutPhis(TTY.out()); + } + + assert block.lir() != null : "must have LIR"; + if (C1XOptions.CommentedAssembly) { + String st = String.format(" block B%d", block.blockID()); + tasm.blockComment(st); + } + + emitLirList(block.lir()); + } + + void emitLirList(LIRList list) { + doPeephole(list); + + for (LIRInstruction op : list.instructionsList()) { + if (C1XOptions.CommentedAssembly) { + // Only print out branches + if (op.code == LIROpcode.Branch) { + tasm.blockComment(op.toStringWithIdPrefix()); + } + } + if (C1XOptions.PrintLIRWithAssembly && !TTY.isSuppressed()) { + // print out the LIR operation followed by the resulting assembly + TTY.println(op.toStringWithIdPrefix()); + TTY.println(); + } + + op.emitCode(this); + + if (C1XOptions.PrintLIRWithAssembly) { + printAssembly(asm); + } + } + } + + private void printAssembly(AbstractAssembler asm) { + byte[] currentBytes = asm.codeBuffer.copyData(lastDecodeStart, asm.codeBuffer.position()); + if (currentBytes.length > 0) { + String disasm = compilation.runtime.disassemble(currentBytes, lastDecodeStart); + if (disasm.length() != 0) { + TTY.println(disasm); + } else { + TTY.println("Code [+%d]: %d bytes", lastDecodeStart, currentBytes.length); + Util.printBytes(lastDecodeStart, currentBytes, C1XOptions.PrintAssemblyBytesPerLine); + } + } + lastDecodeStart = asm.codeBuffer.position(); + } + + boolean checkNoUnboundLabels() { + for (int i = 0; i < branchTargetBlocks.size() - 1; i++) { + if (!branchTargetBlocks.get(i).label().isBound()) { + TTY.println(String.format("label of block B%d is not bound", branchTargetBlocks.get(i).blockID())); + assert false : "unbound label"; + } + } + + return true; + } + + void emitCall(LIRCall op) { + verifyOopMap(op.info); + + switch (op.code) { + case DirectCall: + emitCallAlignment(op.code); + // fall through + case ConstDirectCall: + if (op.marks != null) { + op.marks.put(XirMark.CALLSITE, tasm.recordMark(null, new Mark[0])); + } + emitDirectCall(op.target, op.info); + break; + case IndirectCall: + emitCallAlignment(op.code); + if (op.marks != null) { + op.marks.put(XirMark.CALLSITE, tasm.recordMark(null, new Mark[0])); + } + emitIndirectCall(op.target, op.info, op.targetAddress()); + break; + case NativeCall: { + emitNativeCall((String) op.target, op.info, op.targetAddress()); + break; + } + case TemplateCall: { + emitTemplateCall(op.targetAddress()); + break; + } + default: + throw Util.shouldNotReachHere(); + } + } + + void emitOpLabel(LIRLabel op) { + asm.bind(op.label()); + } + + void emitOp1(LIROp1 op) { + switch (op.code) { + case Move: + if (op.moveKind() == LIROp1.LIRMoveKind.Volatile) { + emitVolatileMove(op.operand(), op.result(), op.kind, op.info); + } else { + moveOp(op.operand(), op.result(), op.kind, op.info, op.moveKind() == LIROp1.LIRMoveKind.Unaligned); + } + break; + case Prefetchr: + emitReadPrefetch(op.operand()); + break; + case Prefetchw: + emitReadPrefetch(op.operand()); + break; + case Return: + emitReturn(op.operand()); + break; + case Neg: + emitNegate((LIRNegate) op); + break; + case Lea: + emitLea(op.operand(), op.result()); + break; + case NullCheck: + emitNullCheck(op.operand(), op.info); + break; + case Lsb: + emitSignificantBitOp(false, op.operand(), op.result()); + break; + case Msb: + emitSignificantBitOp(true, op.operand(), op.result()); + break; + default: + throw Util.shouldNotReachHere(); + } + } + + public void emitOp0(LIROp0 op) { + switch (op.code) { + case Label: + throw Util.shouldNotReachHere(); + case Breakpoint: + emitBreakpoint(); + break; + default: + throw Util.shouldNotReachHere(); + } + } + + protected void emitOp2(LIROp2 op) { + switch (op.code) { + case Cmp: + emitCompare(op.condition(), op.operand1(), op.operand2(), op); + break; + + case Cmpl2i: + case Cmpfd2i: + case Ucmpfd2i: + emitCompare2Int(op.code, op.operand1(), op.operand2(), op.result(), op); + break; + + case Cmove: + emitConditionalMove(op.condition(), op.operand1(), op.operand2(), op.result()); + break; + + case Shl: + case Shr: + case Ushr: + if (op.operand2().isConstant()) { + emitShiftOp(op.code, op.operand1(), ((CiConstant) op.operand2()).asInt(), op.result()); + } else { + emitShiftOp(op.code, op.operand1(), op.operand2(), op.result(), op.tmp()); + } + break; + + case Add: + case Sub: + case Mul: + case Div: + case Rem: + emitArithOp(op.code, op.operand1(), op.operand2(), op.result(), op.info); + break; + + case Abs: + case Sqrt: + case Sin: + case Tan: + case Cos: + case Log: + case Log10: + emitIntrinsicOp(op.code, op.operand1(), op.operand2(), op.result(), op); + break; + + case LogicAnd: + case LogicOr: + case LogicXor: + emitLogicOp(op.code, op.operand1(), op.operand2(), op.result()); + break; + + default: + throw Util.shouldNotReachHere(); + } + } + + public void moveOp(CiValue src, CiValue dest, CiKind kind, LIRDebugInfo info, boolean unaligned) { + if (src.isRegister()) { + if (dest.isRegister()) { + assert info == null : "no patching and info allowed here"; + reg2reg(src, dest); + } else if (dest.isStackSlot()) { + assert info == null : "no patching and info allowed here"; + reg2stack(src, dest, kind); + } else if (dest.isAddress()) { + reg2mem(src, dest, kind, info, unaligned); + } else { + throw Util.shouldNotReachHere(); + } + + } else if (src.isStackSlot()) { + assert info == null : "no patching and info allowed here"; + if (dest.isRegister()) { + stack2reg(src, dest, kind); + } else if (dest.isStackSlot()) { + stack2stack(src, dest, kind); + } else { + throw Util.shouldNotReachHere(); + } + + } else if (src.isConstant()) { + if (dest.isRegister()) { + const2reg(src, dest, info); // patching is possible + } else if (dest.isStackSlot()) { + assert info == null : "no patching and info allowed here"; + const2stack(src, dest); + } else if (dest.isAddress()) { + const2mem(src, dest, kind, info); + } else { + throw Util.shouldNotReachHere(); + } + + } else if (src.isAddress()) { + if (dest.isStackSlot()) { + assert info == null && !unaligned; + mem2stack(src, dest, kind); + } else if (dest.isAddress()) { + assert info == null && !unaligned; + mem2mem(src, dest, kind); + } else { + mem2reg(src, dest, kind, info, unaligned); + } + + } else { + throw Util.shouldNotReachHere(src.toString() + ", dest=" + dest.toString() + ", " + kind); + } + } + + public void verifyOopMap(LIRDebugInfo info) { + if (C1XOptions.VerifyPointerMaps) { + // TODO: verify oops + Util.shouldNotReachHere(); + } + } + + protected abstract int initialFrameSizeInBytes(); + + protected abstract void doPeephole(LIRList list); + + protected abstract void emitSlowPath(SlowPath sp); + + public abstract void emitDeoptizationStub(LIRGenerator.DeoptimizationStub stub); + + protected abstract void emitAlignment(); + + protected abstract void emitBreakpoint(); + + protected abstract void emitLea(CiValue src, CiValue dst); + + protected abstract void emitNullCheck(CiValue src, LIRDebugInfo info); + + protected abstract void emitNegate(LIRNegate negate); + + protected abstract void emitMonitorAddress(int monitor, CiValue dst); + + protected abstract void emitStackAllocate(StackBlock src, CiValue dst); + + protected abstract void emitReturn(CiValue inOpr); + + protected abstract void emitReadPrefetch(CiValue inOpr); + + protected abstract void emitVolatileMove(CiValue inOpr, CiValue result, CiKind kind, LIRDebugInfo info); + + protected abstract void emitLogicOp(LIROpcode code, CiValue inOpr1, CiValue inOpr2, CiValue dst); + + protected abstract void emitIntrinsicOp(LIROpcode code, CiValue inOpr1, CiValue inOpr2, CiValue dst, LIROp2 op); + + protected abstract void emitArithOp(LIROpcode code, CiValue inOpr1, CiValue inOpr2, CiValue dst, LIRDebugInfo info); + + protected abstract void emitShiftOp(LIROpcode code, CiValue inOpr1, CiValue inOpr2, CiValue dst, CiValue tmpOpr); + + protected abstract void emitShiftOp(LIROpcode code, CiValue inOpr1, int asJint, CiValue dst); + + protected abstract void emitSignificantBitOp(boolean most, CiValue inOpr1, CiValue dst); + + protected abstract void emitConditionalMove(Condition condition, CiValue inOpr1, CiValue inOpr2, CiValue dst); + + protected abstract void emitCompare2Int(LIROpcode code, CiValue inOpr1, CiValue inOpr2, CiValue dst, LIROp2 op); + + protected abstract void emitCompare(Condition condition, CiValue inOpr1, CiValue inOpr2, LIROp2 op); + + protected abstract void emitBranch(LIRBranch branch); + + protected abstract void emitTableSwitch(LIRTableSwitch tableSwitch); + + protected abstract void emitConvert(LIRConvert convert); + + protected abstract void emitOp3(LIROp3 op3); + + protected abstract void emitCompareAndSwap(LIRCompareAndSwap compareAndSwap); + + protected abstract void emitXir(LIRXirInstruction xirInstruction); + + protected abstract void emitIndirectCall(Object target, LIRDebugInfo info, CiValue callAddress); + + protected abstract void emitDirectCall(Object target, LIRDebugInfo info); + + protected abstract void emitNativeCall(String symbol, LIRDebugInfo info, CiValue callAddress); + + protected abstract void emitTemplateCall(CiValue address); + + protected abstract void emitCallAlignment(LIROpcode code); + + protected abstract void emitMemoryBarriers(int barriers); + + protected abstract void reg2stack(CiValue src, CiValue dest, CiKind kind); + + protected abstract void reg2mem(CiValue src, CiValue dest, CiKind kind, LIRDebugInfo info, boolean unaligned); + + protected abstract void mem2reg(CiValue src, CiValue dest, CiKind kind, LIRDebugInfo info, boolean unaligned); + + protected abstract void const2mem(CiValue src, CiValue dest, CiKind kind, LIRDebugInfo info); + + protected abstract void const2stack(CiValue src, CiValue dest); + + protected abstract void const2reg(CiValue src, CiValue dest, LIRDebugInfo info); + + protected abstract void mem2stack(CiValue src, CiValue dest, CiKind kind); + + protected abstract void mem2mem(CiValue src, CiValue dest, CiKind kind); + + protected abstract void stack2stack(CiValue src, CiValue dest, CiKind kind); + + protected abstract void stack2reg(CiValue src, CiValue dest, CiKind kind); + + protected abstract void reg2reg(CiValue src, CiValue dest); + +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRBlock.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRBlock.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,259 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.lir; + +import java.util.*; + +import com.oracle.max.asm.*; +import com.oracle.max.graal.compiler.alloc.*; +import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.compiler.util.*; +import com.oracle.max.graal.compiler.value.*; +import com.oracle.max.graal.graph.*; +import com.sun.cri.ci.*; + +/** + * The {@code LIRBlock} class definition. + */ +public final class LIRBlock { + + public final Label label = new Label(); + private LIRList lir; + private final int blockID; + private FrameState lastState; + private List instructions = new ArrayList(4); + private List predecessors = new ArrayList(4); + private List successors = new ArrayList(4); + + /** + * Bit map specifying which {@linkplain OperandPool operands} are live upon entry to this block. + * These are values used in this block or any of its successors where such value are not defined + * in this block. + * The bit index of an operand is its {@linkplain OperandPool#operandNumber(com.sun.cri.ci.CiValue) operand number}. + */ + public CiBitMap liveIn; + + /** + * Bit map specifying which {@linkplain OperandPool operands} are live upon exit from this block. + * These are values used in a successor block that are either defined in this block or were live + * upon entry to this block. + * The bit index of an operand is its {@linkplain OperandPool#operandNumber(com.sun.cri.ci.CiValue) operand number}. + */ + public CiBitMap liveOut; + + /** + * Bit map specifying which {@linkplain OperandPool operands} are used (before being defined) in this block. + * That is, these are the values that are live upon entry to the block. + * The bit index of an operand is its {@linkplain OperandPool#operandNumber(com.sun.cri.ci.CiValue) operand number}. + */ + public CiBitMap liveGen; + + /** + * Bit map specifying which {@linkplain OperandPool operands} are defined/overwritten in this block. + * The bit index of an operand is its {@linkplain OperandPool#operandNumber(com.sun.cri.ci.CiValue) operand number}. + */ + public CiBitMap liveKill; + + private int firstLirInstructionID; + private int lastLirInstructionID; + public int blockEntryPco; + + public LIRBlock(int blockID) { + this.blockID = blockID; + loopIndex = -1; + linearScanNumber = blockID; + } + + public List getInstructions() { + return instructions; + } + + public int firstLirInstructionId() { + return firstLirInstructionID; + } + + public void setFirstLirInstructionId(int firstLirInstructionId) { + this.firstLirInstructionID = firstLirInstructionId; + } + + public int lastLirInstructionId() { + return lastLirInstructionID; + } + + public void setLastLirInstructionId(int lastLirInstructionId) { + this.lastLirInstructionID = lastLirInstructionId; + } + + public int loopDepth; + + public LIRList lir() { + return lir; + } + + public void setLir(LIRList lir) { + this.lir = lir; + } + + public void setBlockEntryPco(int codePos) { + this.blockEntryPco = codePos; + } + + public void printWithoutPhis(LogStream out) { + out.println("LIR Block " + blockID()); + } + + public int blockID() { + return blockID; + } + + public int numberOfPreds() { + return predecessors.size(); + } + + public int numberOfSux() { + return successors.size(); + } + + public boolean isPredecessor(LIRBlock block) { + return predecessors.contains(block); + } + + public LIRBlock predAt(int i) { + return predecessors.get(i); + } + + public LIRBlock suxAt(int i) { + return successors.get(i); + } + + public List blockSuccessors() { + return successors; + } + + @Override + public String toString() { + return "B" + blockID(); + } + + public List blockPredecessors() { + return predecessors; + } + + public int loopDepth() { + // TODO(tw): Set correct loop depth. + return 0; + } + + public int loopIndex() { + return loopIndex; + } + + public void setLoopIndex(int v) { + loopIndex = v; + } + + public void setLoopDepth(int v) { + this.loopDepth = v; + } + + private int loopIndex; + + public Label label() { + return label; + } + + private int linearScanNumber = -1; + private boolean linearScanLoopEnd; + private boolean linearScanLoopHeader; + + public void setLinearScanNumber(int v) { + linearScanNumber = v; + } + + public int linearScanNumber() { + return linearScanNumber; + } + + public void setLinearScanLoopEnd() { + linearScanLoopEnd = true; + } + + public boolean isLinearScanLoopEnd() { + return linearScanLoopEnd; + } + + public void setLinearScanLoopHeader() { + this.linearScanLoopHeader = true; + } + + public boolean isLinearScanLoopHeader() { + return linearScanLoopHeader; + } + + public void replaceWith(LIRBlock other) { + for (LIRBlock pred : predecessors) { + Util.replaceAllInList(this, other, pred.successors); + } + for (int i = 0; i < other.predecessors.size(); ++i) { + if (other.predecessors.get(i) == this) { + other.predecessors.remove(i); + other.predecessors.addAll(i, this.predecessors); + } + } + successors.clear(); + predecessors.clear(); + } + + public void setInstructions(List list) { + instructions = list; + } + + public void setLastState(FrameState fs) { + lastState = fs; + } + + public FrameState lastState() { + return lastState; + } + + private Node first; + private Node last; + + public Node firstInstruction() { + return first; + } + + + public Node lastInstruction() { + return last; + } + + public void setFirstInstruction(Node n) { + first = n; + } + + + public void setLastInstruction(Node n) { + last = n; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRBranch.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRBranch.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.lir; + +import com.oracle.max.asm.*; +import com.oracle.max.graal.compiler.ir.*; +import com.sun.cri.ci.*; + +/** + * @author Marcelo Cintra + * @author Thomas Wuerthinger + * + */ +public class LIRBranch extends LIRInstruction { + + private Condition cond; + private CiKind kind; + private Label label; + + /** + * The target block of this branch. + */ + private LIRBlock block; + + /** + * This is the unordered block for a float branch. + */ + private LIRBlock unorderedBlock; + + + public LIRBranch(Condition cond, Label label) { + this(cond, label, null); + } + + /** + * Creates a new LIRBranch instruction. + * + * @param cond the branch condition + * @param label target label + * + */ + public LIRBranch(Condition cond, Label label, LIRDebugInfo info) { + super(LIROpcode.Branch, CiValue.IllegalValue, info, false); + this.cond = cond; + this.label = label; + } + + /** + * Creates a new LIRBranch instruction. + * + * @param cond + * @param kind + * @param block + * + */ + public LIRBranch(Condition cond, CiKind kind, LIRBlock block) { + super(LIROpcode.Branch, CiValue.IllegalValue, null, false); + this.cond = cond; + this.kind = kind; + this.label = block.label(); + this.block = block; + this.unorderedBlock = null; + } + + public LIRBranch(Condition cond, CiKind kind, LIRBlock block, LIRBlock ublock) { + super(LIROpcode.CondFloatBranch, CiValue.IllegalValue, null, false); + this.cond = cond; + this.kind = kind; + this.label = block.label(); + this.block = block; + this.unorderedBlock = ublock; + } + + /** + * @return the condition + */ + public Condition cond() { + return cond; + } + + public Label label() { + return label; + } + + public LIRBlock block() { + return block; + } + + public LIRBlock unorderedBlock() { + return unorderedBlock; + } + + public void changeBlock(LIRBlock b) { + assert block != null : "must have old block"; + assert block.label() == label() : "must be equal"; + + this.block = b; + this.label = b.label(); + } + + public void changeUblock(LIRBlock b) { + assert unorderedBlock != null : "must have old block"; + this.unorderedBlock = b; + } + + public void negateCondition() { + cond = cond.negate(); + } + + @Override + public void emitCode(LIRAssembler masm) { + masm.emitBranch(this); + } + + @Override + public String operationString(OperandFormatter operandFmt) { + StringBuilder buf = new StringBuilder(cond().operator).append(' '); + if (block() != null) { + buf.append("[B").append(block.blockID()).append(']'); + } else if (label().isBound()) { + buf.append("[label:0x").append(Integer.toHexString(label().position())).append(']'); + } else { + buf.append("[label:??]"); + } + if (unorderedBlock() != null) { + buf.append("unordered: [B").append(unorderedBlock().blockID()).append(']'); + } + return buf.toString(); + } + + public void substitute(LIRBlock oldBlock, LIRBlock newBlock) { + if (block == oldBlock) { + block = newBlock; + LIRInstruction instr = newBlock.lir().instructionsList().get(0); + assert instr instanceof LIRLabel : "first instruction of block must be label"; + label = ((LIRLabel) instr).label(); + } + if (unorderedBlock == oldBlock) { + unorderedBlock = newBlock; + } + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRCall.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRCall.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.lir; + +import java.util.*; + +import com.sun.cri.ci.*; +import com.sun.cri.ci.CiTargetMethod.*; +import com.sun.cri.ri.*; +import com.sun.cri.xir.CiXirAssembler.*; + +/** + * This class represents a call instruction; either to a {@linkplain CiRuntimeCall runtime method}, + * a {@linkplain RiMethod Java method}, a native function or a global stub. + * + * @author Marcelo Cintra + */ +public class LIRCall extends LIRInstruction { + + /** + * The target of the call. This will be a {@link CiRuntimeCall}, {@link RiMethod} or {@link CiValue} + * object denoting a call to the runtime, a Java method or a native function respectively. + */ + public final Object target; + /** + * The call site needs to be marked if this is non-null. + */ + public final Map marks; + + private final int targetAddressIndex; + + public final List pointerSlots; + + + private static CiValue[] toArray(List arguments) { + return arguments.toArray(new CiValue[arguments.size()]); + } + + public LIRCall(LIROpcode opcode, + Object target, + CiValue result, + List arguments, + LIRDebugInfo info, + Map marks, + boolean calleeSaved, + List pointerSlots) { + super(opcode, result, info, !calleeSaved, 0, 0, toArray(arguments)); + this.marks = marks; + this.pointerSlots = pointerSlots; + if (opcode == LIROpcode.DirectCall) { + this.targetAddressIndex = -1; + } else { + // The last argument is the operand holding the address for the indirect call + this.targetAddressIndex = arguments.size() - 1; + } + this.target = target; + } + + /** + * Emits target assembly code for this instruction. + * + * @param masm the target assembler + */ + @Override + public void emitCode(LIRAssembler masm) { + masm.emitCall(this); + } + + /** + * Returns the receiver for this method call. + * @return the receiver + */ + public CiValue receiver() { + return operand(0); + } + + public RiMethod method() { + return (RiMethod) target; + } + + public CiRuntimeCall runtimeCall() { + return (CiRuntimeCall) target; + } + + public CiValue targetAddress() { + if (targetAddressIndex >= 0) { + return operand(targetAddressIndex); + } + return null; + } + + @Override + public String operationString(OperandFormatter operandFmt) { + StringBuilder buf = new StringBuilder(); + if (result().isLegal()) { + buf.append(operandFmt.format(result())).append(" = "); + } + String targetAddress = null; + if (code == LIROpcode.RuntimeCall) { + buf.append(target); + } else if (code != LIROpcode.DirectCall && code != LIROpcode.ConstDirectCall) { + if (targetAddressIndex >= 0) { + targetAddress = operandFmt.format(targetAddress()); + buf.append(targetAddress); + } + } + buf.append('('); + boolean first = true; + for (LIROperand operandSlot : operands) { + String operand = operandFmt.format(operandSlot.value(this)); + if (!operand.isEmpty() && !operand.equals(targetAddress)) { + if (!first) { + buf.append(", "); + } else { + first = false; + } + buf.append(operand); + } + } + buf.append(')'); + return buf.toString(); + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRCompareAndSwap.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRCompareAndSwap.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.lir; + +import com.sun.cri.ci.*; + +/** + * The {@code LIRCompareAndSwap} class definition. + * + * @author Marcelo Cintra + * + */ +public class LIRCompareAndSwap extends LIRInstruction { + + /** + * Constructs a new LIRCompareAndSwap instruction. + * @param addr + * @param expectedValue + * @param newValue + */ + public LIRCompareAndSwap(LIROpcode opcode, CiValue addr, CiValue expectedValue, CiValue newValue) { + super(opcode, CiValue.IllegalValue, null, false, 0, 0, addr, expectedValue, newValue); + } + + /** + * Gets the address of compare and swap. + * + * @return the address + */ + public CiValue address() { + return operand(0); + } + + /** + * Gets the cmpValue of this class. + * + * @return the cmpValue + */ + public CiValue expectedValue() { + return operand(1); + } + + /** + * Gets the newValue of this class. + * + * @return the newValue + */ + public CiValue newValue() { + return operand(2); + } + + /** + * Emits target assembly code for this instruction. + * + * @param masm the target assembler + */ + @Override + public void emitCode(LIRAssembler masm) { + masm.emitCompareAndSwap(this); + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRConvert.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRConvert.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.lir; + +import com.oracle.max.graal.compiler.globalstub.*; +import com.sun.cri.bytecode.*; +import com.sun.cri.ci.*; + +/** + * The {@code LIRConvert} class definition. + * + * @author Marcelo Cintra + * + */ +public class LIRConvert extends LIROp1 { + + public final int bytecode; + public GlobalStub globalStub; + + /** + * Constructs a new instruction LIRConvert for a given operand. + * + * @param bytecode the opcode of the bytecode for this conversion + * @param operand the input operand for this instruction + * @param result the result operand for this instruction + */ + public LIRConvert(int bytecode, CiValue operand, CiValue result) { + super(LIROpcode.Convert, operand, result); + this.bytecode = bytecode; + } + + /** + * Emits target assembly code for this LIRConvert instruction. + * + * @param masm the LIRAssembler + */ + @Override + public void emitCode(LIRAssembler masm) { + masm.emitConvert(this); + } + + /** + * Prints this instruction to a LogStream. + */ + @Override + public String operationString(OperandFormatter operandFmt) { + return "[" + Bytecodes.nameOf(bytecode) + "] " + super.operationString(operandFmt); + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRDebugInfo.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRDebugInfo.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.lir; + +import com.oracle.max.graal.compiler.*; +import com.oracle.max.graal.compiler.ir.*; +import com.oracle.max.graal.compiler.value.*; +import com.sun.cri.ci.*; + +/** + * This class represents debugging and deoptimization information attached to a LIR instruction. + */ +public class LIRDebugInfo { + + public abstract static class ValueLocator { + public abstract CiValue getLocation(Value value); + } + + public final FrameState state; + private LIRBlock exceptionEdge; + public CiDebugInfo debugInfo; + + public LIRDebugInfo(FrameState state) { + assert state != null; + this.state = state; + } + + public LIRBlock exceptionEdge() { + return exceptionEdge; + } + + public void setExceptionEdge(LIRBlock exceptionEdge) { + this.exceptionEdge = exceptionEdge; + } + + private LIRDebugInfo(LIRDebugInfo info) { + this.state = info.state; + this.exceptionEdge = info.exceptionEdge; + } + + public LIRDebugInfo copy() { + return new LIRDebugInfo(this); + } + + public void setOop(CiValue location, C1XCompilation compilation, CiBitMap frameRefMap, CiBitMap regRefMap) { + CiTarget target = compilation.target; + if (location.isAddress()) { + CiAddress stackLocation = (CiAddress) location; + assert stackLocation.index.isIllegal(); + if (stackLocation.base == CiRegister.Frame.asValue()) { + int offset = stackLocation.displacement; + assert offset % target.wordSize == 0 : "must be aligned"; + int stackMapIndex = offset / target.wordSize; + setBit(frameRefMap, stackMapIndex); + } + } else if (location.isStackSlot()) { + CiStackSlot stackSlot = (CiStackSlot) location; + assert !stackSlot.inCallerFrame(); + assert target.spillSlotSize == target.wordSize; + setBit(frameRefMap, stackSlot.index()); + } else { + assert location.isRegister() : "objects can only be in a register"; + CiRegisterValue registerLocation = (CiRegisterValue) location; + int reg = registerLocation.reg.number; + assert reg >= 0 : "object cannot be in non-object register " + registerLocation.reg; + assert reg < target.arch.registerReferenceMapBitCount; + setBit(regRefMap, reg); + } + } + + public CiDebugInfo debugInfo() { + assert debugInfo != null : "debug info not allocated yet"; + return debugInfo; + } + + public boolean hasDebugInfo() { + return debugInfo != null; + } + + public static void setBit(CiBitMap refMap, int bit) { + assert !refMap.get(bit) : "Ref map entry " + bit + " is already set."; + refMap.set(bit); + } + + @Override + public String toString() { + return state.toString(); + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRInstruction.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRInstruction.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,543 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.lir; + +import static com.oracle.max.graal.compiler.C1XCompilation.*; + +import java.util.*; + +import com.oracle.max.graal.compiler.*; +import com.oracle.max.graal.compiler.lir.LIROperand.*; +import com.sun.cri.ci.*; + +/** + * The {@code LIRInstruction} class definition. + * + * @author Marcelo Cintra + * @author Thomas Wuerthinger + */ +public abstract class LIRInstruction { + + private static final LIROperand ILLEGAL_SLOT = new LIROperand(CiValue.IllegalValue); + + private static final CiValue[] NO_OPERANDS = {}; + + public static final OperandMode[] OPERAND_MODES = OperandMode.values(); + + /** + * Constants denoting how a LIR instruction uses an operand. Any combination of these modes + * can be applied to an operand as long as every operand has at least one mode applied to it. + */ + public enum OperandMode { + /** + * An operand that is defined by a LIR instruction and is live after the code emitted for a LIR instruction. + */ + Output, + + /** + * An operand that is used by a LIR instruction and is live before the code emitted for a LIR instruction. + * Unless such an operand is also an output or temp operand, it must not be modified by a LIR instruction. + */ + Input, + + /** + * An operand that is both modified and used by a LIR instruction. + */ + Temp + } + + /** + * The opcode of this instruction. + */ + public final LIROpcode code; + + /** + * The result operand for this instruction. + */ + private final LIROperand result; + + /** + * The input and temporary operands of this instruction. + */ + protected final LIROperand[] operands; + + /** + * Used to emit debug information. + */ + public final LIRDebugInfo info; + + /** + * Value id for register allocation. + */ + public int id; + + /** + * Determines if all caller-saved registers are destroyed by this instruction. + */ + public final boolean hasCall; + + /** + * The number of variable or register output operands for this instruction. + * These operands are at indexes {@code [0 .. allocatorOutputCount-1]} in {@link #allocatorOperands}. + * + * @see OperandMode#Output + */ + private byte allocatorOutputCount; + + /** + * The number of variable or register input operands for this instruction. + * These operands are at indexes {@code [allocatorOutputCount .. (allocatorInputCount+allocatorOutputCount-1)]} in {@link #allocatorOperands}. + * + * @see OperandMode#Input + */ + private byte allocatorInputCount; + + /** + * The number of variable or register temp operands for this instruction. + * These operands are at indexes {@code [allocatorInputCount+allocatorOutputCount .. (allocatorTempCount+allocatorInputCount+allocatorOutputCount-1)]} in {@link #allocatorOperands}. + * + * @see OperandMode#Temp + */ + private byte allocatorTempCount; + + /** + * The number of variable or register input or temp operands for this instruction. + */ + private byte allocatorTempInputCount; + + /** + * The set of operands that must be known to the register allocator either to bind a register + * or stack slot to a {@linkplain CiVariable variable} or to inform the allocator about operands + * that are already fixed to a specific register. + * This set excludes all constant operands as well as operands that are bound to + * a stack slot in the {@linkplain CiStackSlot#inCallerFrame() caller's frame}. + * This array is partitioned as follows. + *
+     *
+     *   <-- allocatorOutputCount --> <-- allocatorInputCount --> <-- allocatorTempCount -->
+     *  +----------------------------+---------------------------+--------------------------+
+     *  |       output operands      |       input operands      |      temp operands       |
+     *  +----------------------------+---------------------------+--------------------------+
+     *
+     * 
+ */ + final List allocatorOperands; + + /** + * Constructs a new LIR instruction that has no input or temp operands. + * + * @param opcode the opcode of the new instruction + * @param result the operand that holds the operation result of this instruction. This will be + * {@link CiValue#IllegalValue} for instructions that do not produce a result. + * @param info the {@link LIRDebugInfo} info that is to be preserved for the instruction. This will be {@code null} when no debug info is required for the instruction. + * @param hasCall specifies if all caller-saved registers are destroyed by this instruction + */ + public LIRInstruction(LIROpcode opcode, CiValue result, LIRDebugInfo info, boolean hasCall) { + this(opcode, result, info, hasCall, 0, 0, NO_OPERANDS); + } + + /** + * Constructs a new LIR instruction. The {@code operands} array is partitioned as follows: + *
+     *
+     *                              <------- tempInput -------> <--------- temp --------->
+     *  +--------------------------+---------------------------+--------------------------+
+     *  |       input operands     |   input+temp operands     |      temp operands       |
+     *  +--------------------------+---------------------------+--------------------------+
+     *
+     * 
+ * + * @param opcode the opcode of the new instruction + * @param result the operand that holds the operation result of this instruction. This will be + * {@link CiValue#IllegalValue} for instructions that do not produce a result. + * @param info the {@link LIRDebugInfo} that is to be preserved for the instruction. This will be {@code null} when no debug info is required for the instruction. + * @param hasCall specifies if all caller-saved registers are destroyed by this instruction + * @param tempInput the number of operands that are both {@linkplain OperandMode#Input input} and {@link OperandMode#Temp temp} operands for this instruction + * @param temp the number of operands that are {@link OperandMode#Temp temp} operands for this instruction + * @param operands the input and temp operands for the instruction + */ + public LIRInstruction(LIROpcode opcode, CiValue result, LIRDebugInfo info, boolean hasCall, int tempInput, int temp, CiValue... operands) { + this.code = opcode; + this.info = info; + this.hasCall = hasCall; + + assert opcode != LIROpcode.Move || result != CiValue.IllegalValue; + allocatorOperands = new ArrayList(operands.length + 3); + this.result = initOutput(result); + + C1XMetrics.LIRInstructions++; + + if (opcode == LIROpcode.Move) { + C1XMetrics.LIRMoveInstructions++; + } + id = -1; + this.operands = new LIROperand[operands.length]; + initInputsAndTemps(tempInput, temp, operands); + + assert verifyOperands(); + } + + private LIROperand initOutput(CiValue output) { + assert output != null; + if (output != CiValue.IllegalValue) { + if (output.isAddress()) { + return addAddress((CiAddress) output); + } + if (output.isStackSlot()) { + return new LIROperand(output); + } + + assert allocatorOperands.size() == allocatorOutputCount; + allocatorOperands.add(output); + allocatorOutputCount++; + return new LIRVariableOperand(allocatorOperands.size() - 1); + } else { + return ILLEGAL_SLOT; + } + } + + /** + * Adds a {@linkplain CiValue#isLegal() legal} value that is part of an address to + * the list of {@linkplain #allocatorOperands register allocator operands}. If + * the value is {@linkplain CiVariable variable}, then its index into the list + * of register allocator operands is returned. Otherwise, {@code -1} is returned. + */ + private int addAddressPart(CiValue part) { + if (part.isRegister()) { + allocatorInputCount++; + allocatorOperands.add(part); + return -1; + } + if (part.isVariable()) { + allocatorInputCount++; + allocatorOperands.add(part); + return allocatorOperands.size() - 1; + } + assert part.isIllegal(); + return -1; + } + + private LIROperand addAddress(CiAddress address) { + assert address.base.isVariableOrRegister(); + + int base = addAddressPart(address.base); + int index = addAddressPart(address.index); + + if (base != -1 || index != -1) { + return new LIRAddressOperand(base, index, address); + } + + assert address.base.isRegister() && (address.index.isIllegal() || address.index.isRegister()); + return new LIROperand(address); + } + + private LIROperand addOperand(CiValue operand, boolean isInput, boolean isTemp) { + assert operand != null; + if (operand != CiValue.IllegalValue) { + assert !(operand.isAddress()); + if (operand.isStackSlot()) { + // no variables to add + return new LIROperand(operand); + } else if (operand.isConstant()) { + // no variables to add + return new LIROperand(operand); + } else { + assert allocatorOperands.size() == allocatorOutputCount + allocatorInputCount + allocatorTempInputCount + allocatorTempCount; + allocatorOperands.add(operand); + + if (isInput && isTemp) { + allocatorTempInputCount++; + } else if (isInput) { + allocatorInputCount++; + } else { + assert isTemp; + allocatorTempCount++; + } + + return new LIRVariableOperand(allocatorOperands.size() - 1); + } + } else { + return ILLEGAL_SLOT; + } + } + + /** + * Gets an input or temp operand of this instruction. + * + * @param index the index of the operand requested + * @return the {@code index}'th operand + */ + public final CiValue operand(int index) { + if (index >= operands.length) { + return CiValue.IllegalValue; + } + + return operands[index].value(this); + } + + private void initInputsAndTemps(int tempInputCount, int tempCount, CiValue[] operands) { + + // Addresses in instruction + for (int i = 0; i < operands.length; i++) { + CiValue op = operands[i]; + if (op.isAddress()) { + this.operands[i] = addAddress((CiAddress) op); + } + } + + int z = 0; + // Input-only operands + for (int i = 0; i < operands.length - tempInputCount - tempCount; i++) { + if (this.operands[z] == null) { + this.operands[z] = addOperand(operands[z], true, false); + } + z++; + } + + // Operands that are both inputs and temps + for (int i = 0; i < tempInputCount; i++) { + if (this.operands[z] == null) { + this.operands[z] = addOperand(operands[z], true, true); + } + z++; + } + + // Temp-only operands + for (int i = 0; i < tempCount; i++) { + if (this.operands[z] == null) { + this.operands[z] = addOperand(operands[z], false, true); + } + z++; + } + } + + private boolean verifyOperands() { + for (LIROperand operandSlot : operands) { + assert operandSlot != null; + } + + for (CiValue operand : this.allocatorOperands) { + assert operand != null; + assert operand.isVariableOrRegister() : "LIR operands can only be variables and registers initially, not " + operand.getClass().getSimpleName(); + } + return true; + } + + /** + * Gets the result operand for this instruction. + * + * @return return the result operand + */ + public final CiValue result() { + return result.value(this); + } + + /** + * Gets the instruction name. + * + * @return the name of the enum constant that represents the instruction opcode, exactly as declared in the enum + * LIROpcode declaration. + */ + public String name() { + return code.name(); + } + + /** + * Abstract method to be used to emit target code for this instruction. + * + * @param masm the target assembler. + */ + public abstract void emitCode(LIRAssembler masm); + + /** + * Utility for specializing how a {@linkplain CiValue LIR operand} is formatted to a string. + * The {@linkplain OperandFormatter#DEFAULT default formatter} returns the value of + * {@link CiValue#toString()}. + */ + public static class OperandFormatter { + public static final OperandFormatter DEFAULT = new OperandFormatter(); + + /** + * Formats a given operand as a string. + * + * @param operand the operand to format + * @return {@code operand} as a string + */ + public String format(CiValue operand) { + return operand.toString(); + } + } + + /** + * Gets the operation performed by this instruction in terms of its operands as a string. + */ + public String operationString(OperandFormatter operandFmt) { + StringBuilder buf = new StringBuilder(); + if (result != ILLEGAL_SLOT) { + buf.append(operandFmt.format(result.value(this))).append(" = "); + } + if (operands.length > 1) { + buf.append("("); + } + boolean first = true; + for (LIROperand operandSlot : operands) { + String operand = operandFmt.format(operandSlot.value(this)); + if (!operand.isEmpty()) { + if (!first) { + buf.append(", "); + } else { + first = false; + } + buf.append(operand); + } + } + if (operands.length > 1) { + buf.append(")"); + } + return buf.toString(); + } + + public boolean verify() { + return true; + } + + /** + * Determines if a given opcode is in a given range of valid opcodes. + * + * @param opcode the opcode to be tested. + * @param start the lower bound range limit of valid opcodes + * @param end the upper bound range limit of valid opcodes + */ + protected static boolean isInRange(LIROpcode opcode, LIROpcode start, LIROpcode end) { + return start.ordinal() < opcode.ordinal() && opcode.ordinal() < end.ordinal(); + } + + public boolean hasOperands() { + if (info != null || hasCall) { + return true; + } + return allocatorOperands.size() > 0; + } + + public final int operandCount(OperandMode mode) { + if (mode == OperandMode.Output) { + return allocatorOutputCount; + } else if (mode == OperandMode.Input) { + return allocatorInputCount + allocatorTempInputCount; + } else { + assert mode == OperandMode.Temp; + return allocatorTempInputCount + allocatorTempCount; + } + } + + public final CiValue operandAt(OperandMode mode, int index) { + if (mode == OperandMode.Output) { + assert index < allocatorOutputCount; + return allocatorOperands.get(index); + } else if (mode == OperandMode.Input) { + assert index < allocatorInputCount + allocatorTempInputCount; + return allocatorOperands.get(index + allocatorOutputCount); + } else { + assert mode == OperandMode.Temp; + assert index < allocatorTempInputCount + allocatorTempCount; + return allocatorOperands.get(index + allocatorOutputCount + allocatorInputCount); + } + } + + public final void setOperandAt(OperandMode mode, int index, CiValue location) { + assert index < operandCount(mode); + assert location.kind != CiKind.Illegal; + assert operandAt(mode, index).isVariable(); + if (mode == OperandMode.Output) { + assert index < allocatorOutputCount; + allocatorOperands.set(index, location); + } else if (mode == OperandMode.Input) { + assert index < allocatorInputCount + allocatorTempInputCount; + allocatorOperands.set(index + allocatorOutputCount, location); + } else { + assert mode == OperandMode.Temp; + assert index < allocatorTempInputCount + allocatorTempCount; + allocatorOperands.set(index + allocatorOutputCount + allocatorInputCount, location); + } + } + + public final LIRBlock exceptionEdge() { + return (info == null) ? null : info.exceptionEdge(); + } + + @Override + public String toString() { + return toString(OperandFormatter.DEFAULT); + } + + public final String toStringWithIdPrefix() { + if (id != -1) { + return String.format("%4d %s", id, toString()); + } + return " " + toString(); + } + + protected static String refMapToString(CiDebugInfo debugInfo, OperandFormatter operandFmt) { + StringBuilder buf = new StringBuilder(); + if (debugInfo.hasStackRefMap()) { + CiBitMap bm = debugInfo.frameRefMap; + for (int slot = bm.nextSetBit(0); slot >= 0; slot = bm.nextSetBit(slot + 1)) { + if (buf.length() != 0) { + buf.append(", "); + } + buf.append(operandFmt.format(CiStackSlot.get(CiKind.Object, slot))); + } + } + if (debugInfo.hasRegisterRefMap()) { + CiBitMap bm = debugInfo.registerRefMap; + for (int reg = bm.nextSetBit(0); reg >= 0; reg = bm.nextSetBit(reg + 1)) { + if (buf.length() != 0) { + buf.append(", "); + } + CiRegisterValue register = compilation().target.arch.registers[reg].asValue(CiKind.Object); + buf.append(operandFmt.format(register)); + } + } + return buf.toString(); + } + + protected void appendDebugInfo(StringBuilder buf, OperandFormatter operandFmt, LIRDebugInfo info) { + if (info != null) { + buf.append(" [bci:").append(info.state.bci); + if (info.hasDebugInfo()) { + CiDebugInfo debugInfo = info.debugInfo(); + String refmap = refMapToString(debugInfo, operandFmt); + if (refmap.length() != 0) { + buf.append(", refmap(").append(refmap.trim()).append(')'); + } + } + buf.append(']'); + } + } + + public String toString(OperandFormatter operandFmt) { + StringBuilder buf = new StringBuilder(name()).append(' ').append(operationString(operandFmt)); + appendDebugInfo(buf, operandFmt, info); + return buf.toString(); + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRLabel.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRLabel.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.lir; + +import com.oracle.max.asm.*; +import com.sun.cri.ci.*; + +/** + * The {@code LIRLabel} class definition. + * + * @author Marcelo Cintra + */ +public class LIRLabel extends LIROp0 { + + private Label label; + + /** + * Constructs a LIRLabel instruction. + * @param label the label + */ + public LIRLabel(Label label) { + super(LIROpcode.Label, CiValue.IllegalValue, null); + assert label != null; + this.label = label; + } + + /** + * Gets the label associated to this instruction. + * @return the label + */ + public Label label() { + return label; + } + + /** + * Emits target assembly code for this LIRLabel instruction. + * @param masm the LIRAssembler + */ + @Override + public void emitCode(LIRAssembler masm) { + masm.emitOpLabel(this); + } + + /** + * Prints this instruction to a LogStream. + */ + @Override + public String operationString(OperandFormatter operandFmt) { + return label.isBound() ? String.valueOf(label.position()) : "?"; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRList.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRList.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,480 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.lir; + +import java.util.*; + +import com.oracle.max.asm.*; +import com.oracle.max.graal.compiler.*; +import com.oracle.max.graal.compiler.alloc.*; +import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.compiler.gen.*; +import com.oracle.max.graal.compiler.globalstub.*; +import com.oracle.max.graal.compiler.ir.*; +import com.sun.cri.ci.*; +import com.sun.cri.ci.CiTargetMethod.*; +import com.sun.cri.ri.*; +import com.sun.cri.xir.*; +import com.sun.cri.xir.CiXirAssembler.*; + +/** + * This class represents a list of LIR instructions and contains factory methods for creating and appending LIR + * instructions to this list. + */ +public final class LIRList { + + private List operations; + private final LIRGenerator generator; + + private final LIROpcode runtimeCallOp; + + private LIROpcode directCallOp(RiMethod method) { + return C1XOptions.UseConstDirectCall && method.hasCompiledCode() ? LIROpcode.ConstDirectCall : LIROpcode.DirectCall; + } + + public LIRList(LIRGenerator generator) { + this.generator = generator; + this.operations = new ArrayList(8); + runtimeCallOp = C1XOptions.UseConstDirectCall ? LIROpcode.ConstDirectCall : LIROpcode.DirectCall; + } + + private void append(LIRInstruction op) { + if (C1XOptions.PrintIRWithLIR && !TTY.isSuppressed()) { + generator.maybePrintCurrentInstruction(); + TTY.println(op.toStringWithIdPrefix()); + TTY.println(); + } + operations.add(op); + assert op.verify(); + } + + public List instructionsList() { + return operations; + } + + public int length() { + return operations.size(); + } + + public LIRInstruction at(int i) { + return operations.get(i); + } + + public void callDirect(RiMethod method, CiValue result, List arguments, LIRDebugInfo info, Map marks, List pointerSlots) { + append(new LIRCall(directCallOp(method), method, result, arguments, info, marks, false, pointerSlots)); + } + + public void callIndirect(RiMethod method, CiValue result, List arguments, LIRDebugInfo info, Map marks, List pointerSlots) { + append(new LIRCall(LIROpcode.IndirectCall, method, result, arguments, info, marks, false, pointerSlots)); + } + + public void callNative(String symbol, CiValue result, List arguments, LIRDebugInfo info, Map marks) { + append(new LIRCall(LIROpcode.NativeCall, symbol, result, arguments, info, marks, false, null)); + } + + public void templateCall(CiValue result, List arguments) { + append(new LIRCall(LIROpcode.TemplateCall, null, result, arguments, null, null, false, null)); + } + + public void membar(int barriers) { + append(new LIRMemoryBarrier(barriers)); + } + + public void branchDestination(Label lbl) { + append(new LIRLabel(lbl)); + } + + public void negate(CiValue src, CiValue dst, GlobalStub globalStub) { + LIRNegate op = new LIRNegate(src, dst); + op.globalStub = globalStub; + append(op); + } + + public void lea(CiValue src, CiValue dst) { + append(new LIROp1(LIROpcode.Lea, src, dst)); + } + + public void unalignedMove(CiValue src, CiValue dst) { + append(new LIROp1(LIROp1.LIRMoveKind.Unaligned, src, dst, dst.kind, null)); + } + + public void move(CiAddress src, CiValue dst, LIRDebugInfo info) { + append(new LIROp1(LIROpcode.Move, src, dst, src.kind, info)); + } + + public void move(CiValue src, CiAddress dst, LIRDebugInfo info) { + append(new LIROp1(LIROpcode.Move, src, dst, dst.kind, info)); + } + + public void move(CiValue src, CiValue dst, CiKind kind) { + append(new LIROp1(LIROpcode.Move, src, dst, kind, null)); + } + + public void move(CiValue src, CiValue dst) { + append(new LIROp1(LIROpcode.Move, src, dst, dst.kind, null)); + } + + public void volatileMove(CiValue src, CiValue dst, CiKind kind, LIRDebugInfo info) { + append(new LIROp1(LIROp1.LIRMoveKind.Volatile, src, dst, kind, info)); + } + + public void oop2reg(Object o, CiValue reg) { + append(new LIROp1(LIROpcode.Move, CiConstant.forObject(o), reg)); + } + + public void returnOp(CiValue result) { + append(new LIROp1(LIROpcode.Return, result)); + } + + public void monitorAddress(int monitor, CiValue dst) { + append(new LIRMonitorAddress(dst, monitor)); + } + + public void convert(int code, CiValue left, CiValue dst, GlobalStub globalStub) { + LIRConvert op = new LIRConvert(code, left, dst); + op.globalStub = globalStub; + append(op); + } + + public void logicalAnd(CiValue left, CiValue right, CiValue dst) { + append(new LIROp2(LIROpcode.LogicAnd, left, right, dst)); + } + + public void logicalOr(CiValue left, CiValue right, CiValue dst) { + append(new LIROp2(LIROpcode.LogicOr, left, right, dst)); + } + + public void logicalXor(CiValue left, CiValue right, CiValue dst) { + append(new LIROp2(LIROpcode.LogicXor, left, right, dst)); + } + + public void nullCheck(CiValue opr, LIRDebugInfo info) { + append(new LIROp1(LIROpcode.NullCheck, opr, info)); + } + + public void compareTo(CiValue left, CiValue right, CiValue dst) { + append(new LIROp2(LIROpcode.CompareTo, left, right, dst)); + } + + public void cmp(Condition condition, CiValue left, CiValue right, LIRDebugInfo info) { + append(new LIROp2(LIROpcode.Cmp, condition, left, right, info)); + } + + public void cmp(Condition condition, CiValue left, CiValue right) { + cmp(condition, left, right, null); + } + + public void cmp(Condition condition, CiValue left, int right, LIRDebugInfo info) { + cmp(condition, left, CiConstant.forInt(right), info); + } + + public void cmp(Condition condition, CiValue left, int right) { + cmp(condition, left, right, null); + } + + public void cmove(Condition condition, CiValue src1, CiValue src2, CiValue dst) { + append(new LIROp2(LIROpcode.Cmove, condition, src1, src2, dst)); + } + + public void abs(CiValue from, CiValue to, CiValue tmp) { + append(new LIROp2(LIROpcode.Abs, from, tmp, to)); + } + + public void sqrt(CiValue from, CiValue to, CiValue tmp) { + append(new LIROp2(LIROpcode.Sqrt, from, tmp, to)); + } + + public void log(CiValue from, CiValue to, CiValue tmp) { + append(new LIROp2(LIROpcode.Log, from, tmp, to)); + } + + public void log10(CiValue from, CiValue to, CiValue tmp) { + append(new LIROp2(LIROpcode.Log10, from, tmp, to)); + } + + public void sin(CiValue from, CiValue to, CiValue tmp1, CiValue tmp2) { + append(new LIROp2(LIROpcode.Sin, from, tmp1, to, tmp2)); + } + + public void cos(CiValue from, CiValue to, CiValue tmp1, CiValue tmp2) { + append(new LIROp2(LIROpcode.Cos, from, tmp1, to, tmp2)); + } + + public void tan(CiValue from, CiValue to, CiValue tmp1, CiValue tmp2) { + append(new LIROp2(LIROpcode.Tan, from, tmp1, to, tmp2)); + } + + public void add(CiValue left, CiValue right, CiValue res) { + append(new LIROp2(LIROpcode.Add, left, right, res)); + } + + public void sub(CiValue left, CiValue right, CiValue res) { + append(new LIROp2(LIROpcode.Sub, left, right, res)); + } + + public void mul(CiValue left, CiValue right, CiValue res) { + append(new LIROp2(LIROpcode.Mul, left, right, res)); + } + + public void div(CiValue left, CiValue right, CiValue res, LIRDebugInfo info) { + append(new LIROp2(LIROpcode.Div, left, right, res, info)); + } + + public void rem(CiValue left, CiValue right, CiValue res, LIRDebugInfo info) { + append(new LIROp2(LIROpcode.Rem, left, right, res, info)); + } + + public void jump(LIRBlock block) { + append(new LIRBranch(Condition.TRUE, CiKind.Illegal, block)); + } + + public void branch(Condition cond, Label lbl) { + append(new LIRBranch(cond, lbl)); + } + + public void branch(Condition cond, Label lbl, LIRDebugInfo info) { + append(new LIRBranch(cond, lbl, info)); + } + + public void branch(Condition cond, CiKind kind, LIRBlock block) { + assert kind != CiKind.Float && kind != CiKind.Double : "no fp comparisons"; + append(new LIRBranch(cond, kind, block)); + } + + public void branch(Condition cond, CiKind kind, LIRBlock block, LIRBlock unordered) { + assert kind == CiKind.Float || kind == CiKind.Double : "fp comparisons only"; + append(new LIRBranch(cond, kind, block, unordered)); + } + + public void tableswitch(CiValue index, int lowKey, LIRBlock defaultTargets, LIRBlock[] targets) { + append(new LIRTableSwitch(index, lowKey, defaultTargets, targets)); + } + + public void shiftLeft(CiValue value, int count, CiValue dst) { + shiftLeft(value, CiConstant.forInt(count), dst, CiValue.IllegalValue); + } + + public void shiftRight(CiValue value, int count, CiValue dst) { + shiftRight(value, CiConstant.forInt(count), dst, CiValue.IllegalValue); + } + + public void lcmp2int(CiValue left, CiValue right, CiValue dst) { + append(new LIROp2(LIROpcode.Cmpl2i, left, right, dst)); + } + + public void callRuntime(CiRuntimeCall rtCall, CiValue result, List arguments, LIRDebugInfo info) { + append(new LIRCall(runtimeCallOp, rtCall, result, arguments, info, null, false, null)); + } + + public void breakpoint() { + append(new LIROp0(LIROpcode.Breakpoint)); + } + + public void prefetch(CiAddress addr, boolean isStore) { + append(new LIROp1(isStore ? LIROpcode.Prefetchw : LIROpcode.Prefetchr, addr)); + } + + public void idiv(CiValue left, CiValue right, CiValue res, CiValue tmp, LIRDebugInfo info) { + append(new LIROp3(LIROpcode.Idiv, left, right, tmp, res, info)); + } + + public void irem(CiValue left, CiValue right, CiValue res, CiValue tmp, LIRDebugInfo info) { + append(new LIROp3(LIROpcode.Irem, left, right, tmp, res, info)); + } + + public void ldiv(CiValue left, CiValue right, CiValue res, CiValue tmp, LIRDebugInfo info) { + append(new LIROp3(LIROpcode.Ldiv, left, right, tmp, res, info)); + } + + public void lrem(CiValue left, CiValue right, CiValue res, CiValue tmp, LIRDebugInfo info) { + append(new LIROp3(LIROpcode.Lrem, left, right, tmp, res, info)); + } + + public void lsb(CiValue src, CiValue dst) { + append(new LIRSignificantBit(LIROpcode.Lsb, src, dst)); + } + + public void msb(CiValue src, CiValue dst) { + append(new LIRSignificantBit(LIROpcode.Msb, src, dst)); + } + + public void wdiv(CiValue left, CiValue right, CiValue res, CiValue tmp, LIRDebugInfo info) { + append(new LIROp3(LIROpcode.Wdiv, left, right, tmp, res, info)); + } + + public void wrem(CiValue left, CiValue right, CiValue res, CiValue tmp, LIRDebugInfo info) { + append(new LIROp3(LIROpcode.Wrem, left, right, tmp, res, info)); + } + + public void wdivi(CiValue left, CiValue right, CiValue res, CiValue tmp, LIRDebugInfo info) { + append(new LIROp3(LIROpcode.Wdivi, left, right, tmp, res, info)); + } + + public void wremi(CiValue left, CiValue right, CiValue res, CiValue tmp, LIRDebugInfo info) { + append(new LIROp3(LIROpcode.Wremi, left, right, tmp, res, info)); + } + + public void cmpMemInt(Condition condition, CiValue base, int disp, int c, LIRDebugInfo info) { + append(new LIROp2(LIROpcode.Cmp, condition, new CiAddress(CiKind.Int, base, disp), CiConstant.forInt(c), info)); + } + + public void cmpRegMem(Condition condition, CiValue reg, CiAddress addr, LIRDebugInfo info) { + append(new LIROp2(LIROpcode.Cmp, condition, reg, addr, info)); + } + + public void shiftLeft(CiValue value, CiValue count, CiValue dst, CiValue tmp) { + append(new LIROp2(LIROpcode.Shl, value, count, dst, tmp)); + } + + public void shiftRight(CiValue value, CiValue count, CiValue dst, CiValue tmp) { + append(new LIROp2(LIROpcode.Shr, value, count, dst, tmp)); + } + + public void unsignedShiftRight(CiValue value, CiValue count, CiValue dst, CiValue tmp) { + append(new LIROp2(LIROpcode.Ushr, value, count, dst, tmp)); + } + + public void fcmp2int(CiValue left, CiValue right, CiValue dst, boolean isUnorderedLess) { + append(new LIROp2(isUnorderedLess ? LIROpcode.Ucmpfd2i : LIROpcode.Cmpfd2i, left, right, dst)); + } + + public void casLong(CiValue addr, CiValue cmpValue, CiValue newValue) { + // Compare and swap produces condition code "zero" if contentsOf(addr) == cmpValue, + // implying successful swap of newValue into addr + append(new LIRCompareAndSwap(LIROpcode.CasLong, addr, cmpValue, newValue)); + } + + public void casObj(CiValue addr, CiValue cmpValue, CiValue newValue) { + // Compare and swap produces condition code "zero" if contentsOf(addr) == cmpValue, + // implying successful swap of newValue into addr + append(new LIRCompareAndSwap(LIROpcode.CasObj, addr, cmpValue, newValue)); + } + + public void casInt(CiValue addr, CiValue cmpValue, CiValue newValue) { + // Compare and swap produces condition code "zero" if contentsOf(addr) == cmpValue, + // implying successful swap of newValue into addr + append(new LIRCompareAndSwap(LIROpcode.CasInt, addr, cmpValue, newValue)); + } + + public void store(CiValue src, CiAddress dst, LIRDebugInfo info) { + append(new LIROp1(LIROpcode.Move, src, dst, dst.kind, info)); + } + + public void load(CiAddress src, CiValue dst, LIRDebugInfo info) { + append(new LIROp1(LIROpcode.Move, src, dst, src.kind, info)); + } + + public static void printBlock(LIRBlock x) { + // print block id + TTY.print("B%d ", x.blockID()); + + // print flags + if (x.isLinearScanLoopHeader()) { + TTY.print("lh "); + } + if (x.isLinearScanLoopEnd()) { + TTY.print("le "); + } + + // print block bci range + TTY.print("[%d, %d] ", -1, -1); + + // print predecessors and successors + if (x.numberOfPreds() > 0) { + TTY.print("preds: "); + for (int i = 0; i < x.numberOfPreds(); i++) { + TTY.print("B%d ", x.predAt(i).blockID()); + } + } + + if (x.numberOfSux() > 0) { + TTY.print("sux: "); + for (int i = 0; i < x.numberOfSux(); i++) { + TTY.print("B%d ", x.suxAt(i).blockID()); + } + } + + TTY.println(); + } + + public static void printLIR(List blocks) { + if (TTY.isSuppressed()) { + return; + } + TTY.println("LIR:"); + int i; + for (i = 0; i < blocks.size(); i++) { + LIRBlock bb = blocks.get(i); + printBlock(bb); + TTY.println("__id_Instruction___________________________________________"); + bb.lir().printInstructions(); + } + } + + private void printInstructions() { + for (int i = 0; i < operations.size(); i++) { + TTY.println(operations.get(i).toStringWithIdPrefix()); + TTY.println(); + } + TTY.println(); + } + + public void append(LIRInsertionBuffer buffer) { + assert this == buffer.lirList() : "wrong lir list"; + int n = operations.size(); + + if (buffer.numberOfOps() > 0) { + // increase size of instructions list + for (int i = 0; i < buffer.numberOfOps(); i++) { + operations.add(null); + } + // insert ops from buffer into instructions list + int opIndex = buffer.numberOfOps() - 1; + int ipIndex = buffer.numberOfInsertionPoints() - 1; + int fromIndex = n - 1; + int toIndex = operations.size() - 1; + for (; ipIndex >= 0; ipIndex--) { + int index = buffer.indexAt(ipIndex); + // make room after insertion point + while (index < fromIndex) { + operations.set(toIndex--, operations.get(fromIndex--)); + } + // insert ops from buffer + for (int i = buffer.countAt(ipIndex); i > 0; i--) { + operations.set(toIndex--, buffer.opAt(opIndex--)); + } + } + } + + buffer.finish(); + } + + public void insertBefore(int i, LIRInstruction op) { + operations.add(i, op); + } + + public void xir(XirSnippet snippet, CiValue[] operands, CiValue outputOperand, int tempInputCount, int tempCount, CiValue[] inputOperands, int[] operandIndices, int outputOperandIndex, + LIRDebugInfo info, LIRDebugInfo infoAfter, RiMethod method, List pointerSlots) { + append(new LIRXirInstruction(snippet, operands, outputOperand, tempInputCount, tempCount, inputOperands, operandIndices, outputOperandIndex, info, infoAfter, method, pointerSlots)); + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRMemoryBarrier.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRMemoryBarrier.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2010, 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.lir; + +import com.sun.cri.bytecode.Bytecodes.*; +import com.sun.cri.ci.*; + +/** + * LIR instruction implementing a {@linkplain MemoryBarriers memory barrier}. + * + * @author Doug Simon + */ +public class LIRMemoryBarrier extends LIRInstruction { + + public final int barriers; + + public LIRMemoryBarrier(int barriers) { + super(LIROpcode.Membar, CiValue.IllegalValue, null, false); + this.barriers = barriers; + } + + @Override + public void emitCode(LIRAssembler masm) { + masm.emitMemoryBarriers(barriers); + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRMonitorAddress.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRMonitorAddress.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2010, 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.lir; + +import com.sun.cri.ci.*; + +/** + * LIR instruction used in to represent the address of a monitor object within the stack frame. + * + * @author Doug Simon + */ +public class LIRMonitorAddress extends LIRInstruction { + + public final int monitor; + + public LIRMonitorAddress(CiValue result, int monitor) { + super(LIROpcode.MonitorAddress, result, null, false); + this.monitor = monitor; + } + + @Override + public void emitCode(LIRAssembler masm) { + masm.emitMonitorAddress(monitor, this.result()); + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRNegate.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRNegate.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2010, 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.lir; + +import com.oracle.max.graal.compiler.globalstub.*; +import com.sun.cri.ci.*; + +/** + * The {@code LIRNegate} class definition. + * + * @author Thomas Wuerthinger + * + */ +public class LIRNegate extends LIROp1 { + + public GlobalStub globalStub; + + /** + * Constructs a new instruction LIRNegate for a given operand. + * + * @param operand the input operand for this instruction + * @param result the result operand for this instruction + */ + public LIRNegate(CiValue operand, CiValue result) { + super(LIROpcode.Neg, operand, result); + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIROp0.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIROp0.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.lir; + +import com.sun.cri.ci.*; + +/** + * The {@code LIROp0} class definition. + * + * @author Marcelo Cintra + * + */ +public class LIROp0 extends LIRInstruction { + + /** + * Creates a LIROp0 instruction. + * + * @param opcode the opcode of the new instruction + */ + public LIROp0(LIROpcode opcode) { + this(opcode, CiValue.IllegalValue); + } + + /** + * Creates a LIROp0 instruction. + * + * @param opcode the opcode of the new instruction + * @param result the result operand to the new instruction + */ + public LIROp0(LIROpcode opcode, CiValue result) { + this(opcode, result, null); + } + + /** + * Creates a LIROp0 instruction. + * + * @param opcode the opcode of the new instruction + * @param result the result operand to the new instruction + * @param info used to emit debug information associated to this instruction + */ + public LIROp0(LIROpcode opcode, CiValue result, LIRDebugInfo info) { + super(opcode, result, info, false); + assert isInRange(opcode, LIROpcode.BeginOp0, LIROpcode.EndOp0) : "Opcode " + opcode + " is invalid for a LIROP0 instruction"; + } + + /** + * Emit assembly code for this instruction. + * @param masm the target assembler + */ + @Override + public void emitCode(LIRAssembler masm) { + masm.emitOp0(this); + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIROp1.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIROp1.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.lir; + +import com.oracle.max.graal.compiler.util.*; +import com.sun.cri.ci.*; + +/** + * The {@code LIROp1} class definition. The LIROp1 instruction has only one input operand. + * + * @author Marcelo Cintra + */ +public class LIROp1 extends LIRInstruction { + + public enum LIRMoveKind { + Normal, Volatile, Unaligned + } + + public final CiKind kind; // the operand type + public final LIRMoveKind moveKind; // flag that indicate the kind of move + + /** + * Constructs a new LIROp1 instruction. + * + * @param opcode the instruction's opcode + * @param opr the first input operand + * @param result the operand that holds the result of this instruction + * @param kind the kind of this instruction + * @param info the object holding information needed to emit debug information + */ + public LIROp1(LIROpcode opcode, CiValue opr, CiValue result, CiKind kind, LIRDebugInfo info) { + super(opcode, result, info, false, 0, 0, opr); + this.kind = kind; + this.moveKind = LIRMoveKind.Normal; + assert isInRange(opcode, LIROpcode.BeginOp1, LIROpcode.EndOp1) : "The " + opcode + " is not a valid LIROp1 opcode"; + } + + /** + * Constructs a new LIROp1 instruction. + * + * @param opcode the instruction's opcode + * @param opr the first input operand + * @param result the operand that holds the result of this instruction + * @param kind the kind of this instruction + */ + public LIROp1(LIROpcode opcode, CiValue opr, CiValue result, CiKind kind) { + this(opcode, opr, result, kind, null); + } + + /** + * Constructs a new LIROp1 instruction. + * + * @param opcode the instruction's opcode + * @param opr the first input operand + * @param result the operand that holds the result of this instruction + */ + public LIROp1(LIROpcode opcode, CiValue opr, CiValue result) { + this(opcode, opr, result, CiKind.Illegal); + } + + /** + * Constructs a new LIROp1 instruction. + * + * @param opcode the instruction's opcode + * @param opr the first input operand + */ + public LIROp1(LIROpcode opcode, CiValue opr) { + this(opcode, opr, CiValue.IllegalValue); + } + + /** + * Constructs a new LIROp1 instruction. + * + * @param moveKind the kind of move the instruction represents + * @param operand the single input operand + * @param result the operand that holds the result of this instruction + * @param kind the kind of this instruction + * @param info the object holding information needed to emit debug information + */ + public LIROp1(LIRMoveKind moveKind, CiValue operand, CiValue result, CiKind kind, LIRDebugInfo info) { + super(LIROpcode.Move, result, info, false, 0, 0, operand); + this.kind = kind; + this.moveKind = moveKind; + } + + /** + * Constructs a new LIROp1 instruction. + * + * @param opcode the instruction's opcode + * @param opr the first input operand + * @param info the object holding information needed to emit debug information + */ + public LIROp1(LIROpcode opcode, CiValue opr, LIRDebugInfo info) { + super(opcode, CiValue.IllegalValue, info, false, 0, 0, opr); + this.kind = CiKind.Illegal; + this.moveKind = LIRMoveKind.Normal; + assert isInRange(opcode, LIROpcode.BeginOp1, LIROpcode.EndOp1) : "The " + opcode + " is not a valid LIROp1 opcode"; + } + + /** + * Gets the input operand of this instruction. + * + * @return opr the input operand. + */ + public CiValue operand() { + return operand(0); + } + + /** + * Gets the kind of move of this instruction. + * + * @return flags the constant that represents the move kind. + */ + public LIRMoveKind moveKind() { + assert code == LIROpcode.Move : "The opcode must be of type LIROpcode.Move in LIROp1"; + return moveKind; + } + + @Override + public void emitCode(LIRAssembler masm) { + masm.emitOp1(this); + } + + @Override + public String name() { + if (code == LIROpcode.Move) { + switch (moveKind()) { + case Normal: + return "move"; + case Unaligned: + return "unaligned move"; + case Volatile: + return "volatile_move"; + default: + throw Util.shouldNotReachHere(); + } + } else { + return super.name(); + } + } + + @Override + public boolean verify() { + switch (code) { + case Move: + assert (operand().isLegal()) && (result().isLegal()) : "Operand and result must be valid in a LIROp1 move instruction."; + break; + case NullCheck: + assert operand().isVariableOrRegister() : "Operand must be a register in a LIROp1 null check instruction."; + break; + case Return: + assert operand().isVariableOrRegister() || operand().isIllegal() : "Operand must be (register | illegal) in a LIROp1 return instruction."; + break; + } + return true; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIROp2.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIROp2.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.lir; + +import com.oracle.max.graal.compiler.ir.*; +import com.sun.cri.ci.*; + +/** + * The {@code LIROp2} class represents a LIR instruction that performs an operation on two operands. + * + * @author Marcelo Cintra + * @author Thomas Wuerthinger + * @author Ben L. Titzer + */ +public class LIROp2 extends LIRInstruction { + + final Condition condition; + + /** + * Constructs a new LIROp2 instruction. + * + * @param opcode the instruction's opcode + * @param condition the instruction's condition + * @param opr1 the first input operand + * @param opr2 the second input operand + * @param info the object holding information needed to emit debug information + */ + public LIROp2(LIROpcode opcode, Condition condition, CiValue opr1, CiValue opr2, LIRDebugInfo info) { + super(opcode, CiValue.IllegalValue, info, false, 0, 0, opr1, opr2); + this.condition = condition; + assert opcode == LIROpcode.Cmp : "Instruction opcode should be of type LIROpcode.Cmp"; + } + + /** + * Constructs a new LIROp2 instruction. + * + * @param opcode the instruction's opcode + * @param condition the instruction's condition + * @param opr1 the first input operand + * @param opr2 the second input operand + * @param result the operand that holds the result of this instruction + */ + public LIROp2(LIROpcode opcode, Condition condition, CiValue opr1, CiValue opr2, CiValue result) { + super(opcode, result, null, false, 0, 0, opr1, opr2); + this.condition = condition; + assert opcode == LIROpcode.Cmove : "Instruction opcode should be of type LIROpcode.Cmove"; + } + + /** + * Constructs a new LIROp2 instruction. + * + * @param opcode the instruction's opcode + * @param opr1 the first input operand + * @param opr2 the second input operand + * @param result the operand that holds the result of this instruction + * @param info the object holding information needed to emit debug information + * @param kind the kind of this instruction + */ + public LIROp2(LIROpcode opcode, CiValue opr1, CiValue opr2, CiValue result, LIRDebugInfo info, CiKind kind, boolean hasCall) { + super(opcode, result, info, hasCall, 0, 0, opr1, opr2); + this.condition = null; + assert opcode != LIROpcode.Cmp && isInRange(opcode, LIROpcode.BeginOp2, LIROpcode.EndOp2) : "The " + opcode + " is not a valid LIROp2 opcode"; + } + + /** + * Constructs a new LIROp2 instruction. + * + * @param opcode the instruction's opcode + * @param opr1 the instruction's first operand + * @param opr2 the instruction's second operand + * @param result the operand that holds the result of this instruction + * @param info the object holding information needed to emit debug information + */ + public LIROp2(LIROpcode opcode, CiValue opr1, CiValue opr2, CiValue result, LIRDebugInfo info) { + this(opcode, opr1, opr2, result, info, CiKind.Illegal, false); + } + + /** + * Constructs a new LIROp2 instruction. + * + * @param opcode the instruction's opcode + * @param opr1 the instruction's first operand + * @param opr2 the instruction's second operand + * @param result the operand that holds the result of this instruction + */ + public LIROp2(LIROpcode opcode, CiValue opr1, CiValue opr2, CiValue result) { + this(opcode, opr1, opr2, result, (LIRDebugInfo) null); + } + + /** + * Constructs a new LIROp2 instruction. + * + * @param opcode the instruction's opcode + * @param opr1 the first input operand + * @param opr2 the second input operand + * @param result the operand that holds the result of this instruction + * @param tmp the temporary operand used by this instruction + */ + public LIROp2(LIROpcode opcode, CiValue opr1, CiValue opr2, CiValue result, CiValue tmp) { + super(opcode, result, null, false, 0, 1, opr1, opr2, tmp); + this.condition = null; + assert opcode != LIROpcode.Cmp && isInRange(opcode, LIROpcode.BeginOp2, LIROpcode.EndOp2) : "The " + opcode + " is not a valid LIROp2 opcode"; + } + + /** + * Gets the first input operand. + * + * @return opr1 the first input operand + */ + public CiValue operand1() { + return operand(0); + } + + /** + * Gets the second input operand. + * + * @return opr2 the second input operand + */ + public CiValue operand2() { + return operand(1); + } + + /** + * Gets the temporary operand of this instruction. + * + * @return tmp the temporary operand of this instruction + * + */ + public CiValue tmp() { + return operand(2); + } + + /** + * Gets the condition of this instruction, if it is a Cmp or Cmove LIR instruction. + * + * @return condition the condition of this instruction + */ + public Condition condition() { + assert code == LIROpcode.Cmp || code == LIROpcode.Cmove : "Field access only valid for cmp and cmove"; + return condition; + } + + /** + * Emit target assembly code for this instruction. + * + * @param masm the target assembler + */ + @Override + public void emitCode(LIRAssembler masm) { + masm.emitOp2(this); + } + + /** + * Prints this instruction. + */ + @Override + public String operationString(OperandFormatter operandFmt) { + if (code == LIROpcode.Cmove) { + return condition.toString() + " " + super.operationString(operandFmt); + } + return super.operationString(operandFmt); + } +} + diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIROp3.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIROp3.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.lir; + +import com.sun.cri.ci.*; + +/** + * The {@code LIROp3} class definition. + * + * @author Marcelo Cintra + * + */ +public class LIROp3 extends LIRInstruction { + + /** + * Creates a new LIROp3 instruction. A LIROp3 instruction represents a LIR instruction + * that has three input operands. + * + * @param opcode the instruction's opcode + * @param opr1 the first input operand + * @param opr2 the second input operand + * @param opr3 the third input operand + * @param result the result operand + * @param info the debug information, used for deoptimization, associated to this instruction + */ + public LIROp3(LIROpcode opcode, CiValue opr1, CiValue opr2, CiValue opr3, CiValue result, LIRDebugInfo info) { + super(opcode, result, info, false, 1, 1, opr1, opr2, opr3); + assert isInRange(opcode, LIROpcode.BeginOp3, LIROpcode.EndOp3) : "The " + opcode + " is not a valid LIROp3 opcode"; + } + + /** + * Gets the opr1 of this class. + * + * @return the opr1 + */ + public CiValue opr1() { + return operand(0); + } + + /** + * Gets the opr2 of this class. + * + * @return the opr2 + */ + public CiValue opr2() { + return operand(1); + } + + /** + * Emits assembly code for this instruction. + * + * @param masm the target assembler + */ + @Override + public void emitCode(LIRAssembler masm) { + masm.emitOp3(this); + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIROpcode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIROpcode.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.lir; + +/** + * The {@code LirOpcode} enum represents the Operation code of each LIR instruction. + * + * @author Marcelo Cintra + * @author Thomas Wuerthinger + */ +public enum LIROpcode { + // Checkstyle: stop + // @formatter:off + BeginOp0, + Label, + Breakpoint, + RuntimeCall, + Membar, + Branch, + CondFloatBranch, + EndOp0, + BeginOp1, + NullCheck, + Return, + Lea, + Neg, + TableSwitch, + Move, + Prefetchr, + Prefetchw, + Convert, + Lsb, + Msb, + MonitorAddress, + EndOp1, + BeginOp2, + Cmp, + Cmpl2i, + Ucmpfd2i, + Cmpfd2i, + Cmove, + Add, + Sub, + Mul, + Div, + Rem, + Sqrt, + Abs, + Sin, + Cos, + Tan, + Log, + Log10, + LogicAnd, + LogicOr, + LogicXor, + Shl, + Shr, + Ushr, + CompareTo, + EndOp2, + BeginOp3, + Idiv, + Irem, + Ldiv, + Lrem, + Wdiv, + Wdivi, + Wrem, + Wremi, + EndOp3, + NativeCall, + DirectCall, + ConstDirectCall, + IndirectCall, + TemplateCall, + InstanceOf, + CheckCast, + StoreCheck, + CasLong, + CasWord, + CasObj, + CasInt, + Xir, + // @formatter:on + // Checkstyle: resume +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIROperand.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIROperand.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.lir; + +import com.sun.cri.ci.*; + +/** + * An instruction operand. If the register allocator can modify this operand (e.g. to replace a + * variable with a register), then it will have a corresponding entry in the {@link LIRInstruction#allocatorOperands} + * list of an instruction. + * + * @author Doug Simon + */ +public class LIROperand { + + /** + * The value of the operand. + */ + CiValue value; + + LIROperand(CiValue value) { + this.value = value; + } + + /** + * Gets the value of this operand. This may still be a {@linkplain CiVariable} + * if the register allocator has not yet assigned a register or stack address to the operand. + * + * @param inst the instruction containing this operand + */ + public CiValue value(LIRInstruction inst) { + return value; + } + + @Override + public String toString() { + return value.toString(); + } + + static class LIRVariableOperand extends LIROperand { + /** + * Index into an instruction's {@linkplain LIRInstruction#allocatorOperands allocator operands}. + */ + final int index; + + LIRVariableOperand(int index) { + super(null); + this.index = index; + } + + @Override + public CiValue value(LIRInstruction inst) { + if (value == null) { + CiValue value = inst.allocatorOperands.get(index); + if (value.isVariable()) { + return value; + } + this.value = value; + } + return value; + } + + @Override + public String toString() { + if (value == null) { + return "operands[" + index + "]"; + } + return value.toString(); + } + } + + /** + * An address operand with at least one {@linkplain CiVariable variable} constituent. + */ + static class LIRAddressOperand extends LIROperand { + int base; + int index; + + LIRAddressOperand(int base, int index, CiAddress address) { + super(address); + assert base != -1 || index != -1 : "address should have at least one variable part"; + this.base = base; + this.index = index; + } + + @Override + public CiValue value(LIRInstruction inst) { + if (base != -1 || index != -1) { + CiAddress address = (CiAddress) value; + CiValue baseOperand = base == -1 ? address.base : inst.allocatorOperands.get(base); + CiValue indexOperand = index == -1 ? address.index : inst.allocatorOperands.get(index); + if (address.index.isLegal()) { + assert indexOperand.isVariableOrRegister(); + if (baseOperand.isVariable() || indexOperand.isVariable()) { + return address; + } + } else { + if (baseOperand.isVariable()) { + return address; + } + } + value = new CiAddress(address.kind, baseOperand, indexOperand, address.scale, address.displacement); + base = -1; + index = -1; + } + return value; + } + + @Override + public String toString() { + return value.toString(); + } + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRSignificantBit.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRSignificantBit.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2010, 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.lir; + +import com.sun.cri.bytecode.*; +import com.sun.cri.ci.*; + +/** + * LIR instruction used in translating {@link Bytecodes#LSB} and {@link Bytecodes#MSB}. + * + * @author Doug Simon + */ +public class LIRSignificantBit extends LIRInstruction { + + public LIRSignificantBit(LIROpcode opcode, CiValue operand, CiValue result) { + super(opcode, result, null, false, 1, 0, operand); + } + + @Override + public void emitCode(LIRAssembler masm) { + masm.emitSignificantBitOp(code == LIROpcode.Msb, operand(0), result()); + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRTableSwitch.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRTableSwitch.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.lir; + +import com.sun.cri.ci.*; + +/** + * @author Doug Simon + */ +public class LIRTableSwitch extends LIRInstruction { + + public LIRBlock defaultTarget; + + public final LIRBlock[] targets; + + public final int lowKey; + + public LIRTableSwitch(CiValue value, int lowKey, LIRBlock defaultTarget, LIRBlock[] targets) { + super(LIROpcode.TableSwitch, CiValue.IllegalValue, null, false, 1, 0, value); + this.lowKey = lowKey; + this.targets = targets; + this.defaultTarget = defaultTarget; + } + + @Override + public void emitCode(LIRAssembler masm) { + masm.emitTableSwitch(this); + } + + /** + * @return the input value to this switch + */ + public CiValue value() { + return operand(0); + } + + @Override + public String operationString(OperandFormatter operandFmt) { + StringBuilder buf = new StringBuilder(super.operationString(operandFmt)); + buf.append("\ndefault: [B").append(defaultTarget.blockID()).append(']'); + int key = lowKey; + for (LIRBlock b : targets) { + buf.append("\ncase ").append(key).append(": [B").append(b.blockID()).append(']'); + key++; + } + return buf.toString(); + } + + + private LIRBlock substitute(LIRBlock block, LIRBlock oldBlock, LIRBlock newBlock) { + if (block == oldBlock) { + LIRInstruction instr = newBlock.lir().instructionsList().get(0); + assert instr instanceof LIRLabel : "first instruction of block must be label"; + return newBlock; + } + return oldBlock; + } + + public void substitute(LIRBlock oldBlock, LIRBlock newBlock) { + if (substitute(defaultTarget, oldBlock, newBlock) == newBlock) { + defaultTarget = newBlock; + } + for (int i = 0; i < targets.length; i++) { + if (substitute(targets[i], oldBlock, newBlock) == newBlock) { + targets[i] = newBlock; + } + } + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRXirInstruction.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRXirInstruction.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.lir; + +import java.util.*; + +import com.oracle.max.graal.compiler.*; +import com.oracle.max.graal.compiler.gen.*; +import com.sun.cri.ci.*; +import com.sun.cri.ri.*; +import com.sun.cri.xir.*; + +public class LIRXirInstruction extends LIRInstruction { + + public final CiValue[] originalOperands; + public final int outputOperandIndex; + public final int[] operandIndices; + public final XirSnippet snippet; + public final RiMethod method; + public final int inputTempCount; + public final int tempCount; + public final int inputCount; + public final List pointerSlots; + public final LIRDebugInfo infoAfter; + + public LIRXirInstruction(XirSnippet snippet, + CiValue[] originalOperands, + CiValue outputOperand, + int inputTempCount, + int tempCount, + CiValue[] operands, + int[] operandIndices, + int outputOperandIndex, + LIRDebugInfo info, + LIRDebugInfo infoAfter, + RiMethod method, + List pointerSlots) { + super(LIROpcode.Xir, outputOperand, info, false, inputTempCount, tempCount, operands); + this.infoAfter = infoAfter; + this.pointerSlots = pointerSlots; + assert this.pointerSlots == null || this.pointerSlots.size() >= 0; + this.method = method; + this.snippet = snippet; + this.operandIndices = operandIndices; + this.outputOperandIndex = outputOperandIndex; + this.originalOperands = originalOperands; + this.inputTempCount = inputTempCount; + this.tempCount = tempCount; + this.inputCount = operands.length - inputTempCount - tempCount; + + C1XMetrics.LIRXIRInstructions++; + } + + public CiValue[] getOperands() { + for (int i = 0; i < operandIndices.length; i++) { + originalOperands[operandIndices[i]] = operand(i); + } + if (outputOperandIndex != -1) { + originalOperands[outputOperandIndex] = result(); + } + return originalOperands; + } + + /** + * Emits target assembly code for this instruction. + * + * @param masm the target assembler + */ + @Override + public void emitCode(LIRAssembler masm) { + masm.emitXir(this); + } + + /** + * Prints this instruction. + */ + @Override + public String operationString(OperandFormatter operandFmt) { + return toString(operandFmt); + } + + @Override + public String toString(OperandFormatter operandFmt) { + StringBuilder sb = new StringBuilder(); + sb.append("XIR: "); + + if (result().isLegal()) { + sb.append(operandFmt.format(result()) + " = "); + } + + sb.append(snippet.template); + sb.append("("); + for (int i = 0; i < snippet.arguments.length; i++) { + XirArgument a = snippet.arguments[i]; + if (i > 0) { + sb.append(", "); + } + if (a.constant != null) { + sb.append(operandFmt.format(a.constant)); + } else { + Object o = a.object; + if (o instanceof LIRItem) { + sb.append(operandFmt.format(((LIRItem) o).result())); + } else if (o instanceof CiValue) { + sb.append(operandFmt.format((CiValue) o)); + } else { + sb.append(o); + } + } + } + sb.append(')'); + + if (method != null) { + sb.append(" method="); + sb.append(method.toString()); + } + + + for (LIRInstruction.OperandMode mode : LIRInstruction.OPERAND_MODES) { + int n = operandCount(mode); + if (mode == OperandMode.Output && n <= 1) { + // Already printed single output (i.e. result()) + continue; + } + if (n != 0) { + sb.append(' ').append(mode.name().toLowerCase()).append("=("); + HashSet operands = new HashSet(); + for (int i = 0; i < n; i++) { + String operand = operandFmt.format(operandAt(mode, i)); + if (!operands.contains(operand)) { + if (!operands.isEmpty()) { + sb.append(", "); + } + operands.add(operand); + sb.append(operand); + } + } + sb.append(')'); + } + } + + appendDebugInfo(sb, operandFmt, info); + + return sb.toString(); + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/package-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/package-info.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @author Marcelo Cintra + * @author Thomas Wuerthinger + * + * Port of the backend (LIR) of the client compiler to Java. + */ +package com.oracle.max.graal.compiler.lir; diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/observer/CompilationEvent.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/observer/CompilationEvent.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.observer; + +import java.util.*; + +import com.oracle.max.graal.compiler.*; +import com.oracle.max.graal.compiler.alloc.*; +import com.oracle.max.graal.compiler.graph.*; +import com.oracle.max.graal.graph.*; +import com.sun.cri.ci.*; +import com.sun.cri.ri.*; + +/** + * An event that occurred during compilation. Instances of this class provide information about the event and the state + * of the compilation when the event was raised. {@link #getCompilation()} and {@link #getMethod()} are guaranteed to + * always return a non-{@code null} value. Other objects provided by getter methods may be {@code null}, + * depending on the available information when and where the event was triggered. + * + * @author Peter Hofer + */ +public class CompilationEvent { + + private final C1XCompilation compilation; + private final String label; + private Graph graph; + + private BlockMap blockMap; + private int codeSize = -1; + + private LinearScan allocator; + private CiTargetMethod targetMethod; + private boolean hirValid = false; + private boolean lirValid = false; + + private Interval[] intervals; + private int intervalsSize; + private Interval[] intervalsCopy = null; + + public CompilationEvent(C1XCompilation compilation) { + this(compilation, null); + } + + private CompilationEvent(C1XCompilation compilation, String label) { + assert compilation != null; + this.label = label; + this.compilation = compilation; + } + + public CompilationEvent(C1XCompilation compilation, String label, Graph graph, boolean hirValid, boolean lirValid) { + this(compilation, label); + this.graph = graph; + this.hirValid = hirValid; + this.lirValid = lirValid; + } + + public CompilationEvent(C1XCompilation compilation, String label, Graph graph, boolean hirValid, boolean lirValid, CiTargetMethod targetMethod) { + this(compilation, label, graph, hirValid, lirValid); + this.targetMethod = targetMethod; + } + + public CompilationEvent(C1XCompilation compilation, String label, BlockMap blockMap, int codeSize) { + this(compilation, label); + this.blockMap = blockMap; + this.codeSize = codeSize; + } + + public CompilationEvent(C1XCompilation compilation, String label, LinearScan allocator, Interval[] intervals, int intervalsSize) { + this(compilation, label); + this.allocator = allocator; + this.intervals = intervals; + this.intervalsSize = intervalsSize; + } + + public C1XCompilation getCompilation() { + return compilation; + } + + public String getLabel() { + return label; + } + + public RiMethod getMethod() { + return compilation.method; + } + + public BlockMap getBlockMap() { + return blockMap; + } + + public Graph getGraph() { + return graph; + } + + public LinearScan getAllocator() { + return allocator; + } + + public CiTargetMethod getTargetMethod() { + return targetMethod; + } + + public boolean isHIRValid() { + return hirValid; + } + + public boolean isLIRValid() { + return lirValid; + } + + public Interval[] getIntervals() { + if (intervalsCopy == null && intervals != null) { + // deferred copy of the valid range of the intervals array + intervalsCopy = Arrays.copyOf(intervals, intervalsSize); + } + return intervalsCopy; + } + + public int getCodeSize() { + return codeSize; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/observer/CompilationObserver.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/observer/CompilationObserver.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.observer; + +import com.oracle.max.graal.compiler.*; + +/** + * Interface for classes that observe events of an {@link ObservableCompiler}. + * + * @author Peter Hofer + */ +public interface CompilationObserver { + + /** + * Called when compilation of a method has started. This is always the first event raised for a particular + * {@link C1XCompilation}. + * + * @param event Information associated with the event and current state of the compilation. + */ + void compilationStarted(CompilationEvent event); + + /** + * Called when an event has occurred, for example that a particular phase in the compilation has been entered. + * + * @param event Information associated with the event and current state of the compilation. + */ + void compilationEvent(CompilationEvent event); + + /** + * Called when compilation of a method has completed (successfully or not). This is always the last event raised for + * a particular {@link C1XCompilation}. + * + * @param event Information associated with the event and current state of the compilation. + */ + void compilationFinished(CompilationEvent event); + +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/observer/ObservableCompiler.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/observer/ObservableCompiler.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.observer; + +import java.util.*; + +import com.oracle.max.graal.compiler.debug.*; + +/** + * Base class for compilers that notify subscribed {@link CompilationObserver CompilationObservers} of + * {@link CompilationEvent CompilationEvents} that occur during their compilations. + * + * @author Peter Hofer + */ +public class ObservableCompiler { + + private List observers; + + /** + * @return {@code true} if one or more observers are subscribed to receive notifications from this compiler, + * {@code false} otherwise. + */ + public boolean isObserved() { + return observers != null && !TTY.isSuppressed(); + } + + /** + * Add the specified observer to receive events from this compiler. + * + * @param observer The observer to add. + */ + public void addCompilationObserver(CompilationObserver observer) { + assert observer != null; + + if (observers == null) { + observers = new LinkedList(); + } + observers.add(observer); + } + + public void fireCompilationStarted(CompilationEvent event) { + if (isObserved()) { + for (CompilationObserver observer : observers) { + observer.compilationStarted(event); + } + } + } + + public void fireCompilationEvent(CompilationEvent event) { + if (isObserved()) { + for (CompilationObserver observer : observers) { + observer.compilationEvent(event); + } + } + } + + public void fireCompilationFinished(CompilationEvent event) { + if (isObserved()) { + for (CompilationObserver observer : observers) { + observer.compilationFinished(event); + } + } + } + + /** + * Remove the specified observer so that it no longer receives events from this compiler. + * + * @param observer The observer to remove. + */ + public void removeCompilationObserver(CompilationObserver observer) { + if (observers != null) { + observers.remove(observer); + if (observers.size() == 0) { + observers = null; + } + } + } + +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/observer/package-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/observer/package-info.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * Classes and interfaces for observing compilations. + * + * @author Peter Hofer + */ +package com.oracle.max.graal.compiler.observer; diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/opt/CanonicalizerPhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/opt/CanonicalizerPhase.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.opt; + +import java.util.*; + +import com.oracle.max.graal.compiler.*; +import com.oracle.max.graal.graph.*; + +public class CanonicalizerPhase extends Phase { + + + @Override + protected void run(Graph graph) { + NodeBitMap visited = graph.createNodeBitMap(); + List nodes = new ArrayList(graph.getNodes()); + for (Node n : nodes) { + if (n == null) { + continue; + } + if (!visited.isMarked(n)) { + this.canonicalize(n, visited); + } + } + } + + private void canonicalize(Node n, NodeBitMap visited) { + visited.mark(n); + for (Node input : n.inputs()) { + if (input == null) { + continue; + } + if (!visited.isNew(input) && !visited.isMarked(input)) { + canonicalize(input, visited); + } + } + + CanonicalizerOp op = n.lookup(CanonicalizerOp.class); + if (op != null) { + Node canonical = op.canonical(n); + if (canonical != n) { + n.replace(canonical); + C1XMetrics.NodesCanonicalized++; + } + } + } + + public interface CanonicalizerOp extends Op { + Node canonical(Node node); + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/package-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/package-info.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * The top-level package in C1X containing options, metrics, timers and the main compiler class + * {@link com.oracle.max.graal.compiler.C1XCompiler}. + * + *

{@code C1XCompiler} Overview

+ * + * C1X is intended to be used with multiple JVM's so makes no use of or reference to classes for a specific JVM, for + * example Maxine. + * + * The compiler is represented by the class {@code C1XCompiler}. {@code C1XCompiler} binds a specific target + * architecture and JVM interface to produce a usable compiler object. There are + * two variants of {@code compileMethod}, one of which is used when doing on stack replacement (OSR), discussed + * later. The main variant takes {@link com.sun.cri.ri.RiMethod} and {@link com.sun.cri.xir.RiXirGenerator} arguments. + * {@code RiMethod} is C1X's representation of a Java method and {@code RiXirGenerator} represents the interface through + * which the compiler requests the XIR for a given bytecode from the runtime system. + * + *

The C1X Compilation Process

+ * + * {@link com.oracle.max.graal.compiler.C1XCompiler#compileMethod} creates a {@link C1XCompilation} instance and then returns the result of calling its + * {@link com.oracle.max.graal.compiler.C1XCompilation#compile} method. The {@code C1XCompilation} instance records whether {@code compileMethod} was invoked with + * the OSR variant, which is used later in the IR generation. + *

+ * While there is only one {@code C1XCompiler} instance, there may be several compilations proceeding concurrently, each of + * which is represented by a unique {@code C1XCompilation} instance. The static method {@link com.oracle.max.graal.compiler.C1XCompilation#current}} returns the + * {@code C1XCompilation} instance associated with the current thread, and is managed using a {@link java.lang.ThreadLocal} variable. It + * is used when assigning the unique id that is used for tracing output to an HIR node. Each {@code C1XCompilation} instance + * has an associated {@link com.sun.cri.ci.CiStatistics} object that accumulates information about the compilation process, but is also + * used as a generator of, for example, basic block identifiers. + *

+ * The compilation begins by calling {@link com.oracle.max.graal.compiler.C1XCompilation#emitHIR}, which creates the high-level intermediate representation (HIR) from the + * bytecodes of the method. The HIR is managed by the {@link com.oracle.max.graal.compiler.graph.IR} class, an instance of which is created by + * {@code emitHR}, which then calls the {{@link com.oracle.max.graal.compiler.graph.IR#build}} method and returns the result. The {@code C1XCompilation} and {@code IR} + * instances are are bi-directionally linked. + * + *

Supported backends

+ * + *
    + *
  • AMD64/x64 with SSE2
  • + *
+ * + *

Notes and Todos

This is a collection of notes about the C1X compiler, including future directions, + * refactorings, missing features, broken features, etc. + * + * + *

Anticipated Refactorings

+ * + *
    + *
  • + * The HIR nodes {@link com.oracle.max.graal.compiler.ir.UnsafePrefetch}, {@link com.oracle.max.graal.compiler.ir.UnsafePutObject}, etc should be replaced by uses of the newer + * {@link com.oracle.max.graal.compiler.ir.LoadPointer} and {@link com.oracle.max.graal.compiler.ir.StorePointer} nodes. Currently, the unsafe nodes are only generated by + * the creation of an OSR entry. Benefit: reduce the number of different IR nodes.
  • + * + *
  • + * Add a field to optionally store an {@link com.oracle.max.graal.compiler.ir.Info} object for each HIR node, and remove the + * {@link com.oracle.max.graal.compiler.ir.Instruction#exceptionHandlers} field, the {@link com.oracle.max.graal.compiler.ir.Instruction#bci} field, and any fields to store the Java + * frame state in subclasses. Benefit: saves space if most HIR nodes do not have exception handlers, a bci or Java frame + * state. Removes virtual dispatch on accessing debug information for nodes. Allows any node, regardless of its type, to + * have info attached.
  • + * + *
  • + * Migrate all HIR nodes to use the immutable {@link com.oracle.max.graal.compiler.value.FrameStateInfo} for debugging information. The {@link com.oracle.max.graal.compiler.value.FrameState} + * class is mutable and used throughout graph building. Benefit: {@code FrameStateInfo} would save both total space in + * the IR graph prevent many bugs due to the mutability of {@code FrameState}.
  • + * + *
  • + * Move the {@code FrameState} class to an inner class, or combine entirely, with the {@link com.oracle.max.graal.compiler.graph.GraphBuilder} class. After + * the introduction of the {@code FrameStateInfo} into HIR nodes, the mutable value stack should only need to be + * accessed from the graph builder.
  • + * + *
+ * + *

Missing or incomplete features

+ * + * There are some features of C1 that were not ported forward or finished given the time constraints for the C1X port. A + * list appears below. + * + *
    + *
  • + * Deoptimization metadata. The locations of all local variables and stack values are not communicated back to the + * runtime system through the {@link com.sun.cri.ci.CiDebugInfo} class yet. Such values are known to the register allocator, and there + * vestigial logic to compute them still there in the + * {@link com.oracle.max.graal.compiler.alloc.LinearScan#computeDebugInfo} method. To complete this metadata, the + * {@link com.oracle.max.graal.compiler.alloc.LinearScan} class must implement the {@link ValueLocator} interface and pass it to the + * {@link com.oracle.max.graal.compiler.lir.LIRDebugInfo#createFrame} method after register allocation. The + * resulting debug info will be fed back to the runtime system by the existing logic that calls + * {@link com.sun.cri.ci.CiTargetMethod#recordCall(int, Object, CiDebugInfo, boolean)} and other methods. Obviously the runtime + * system will need to encode this metadata in a dense format, because it is huge.
  • + * + * + *
  • + * Tiered compilation support. C1 supported the ability to add instrumentation to branches, invocations, and checkcasts + * in order to feed profile information to the C2 compiler in a tiered compilation setup. It relied on adding some + * information to the HIR nodes that represent these operations ({@link Invoke}, {@link CheckCast}, etc). All of this + * logic was removed to simplify both the front end and back end in anticipation of designing a future instrumentation + * API. XIR should be general enough to allow instrumentation code to be added to invocation and checkcast sites, but + * currently has no support for adding code at branches. + * + *
  • + * + *
  • + * SPARC and other architecture support. There pretty well-delineated separation between the architecture-independent + * part of LIR backend and the architecture-dependent, but the only implementation that current exists is the X86 + * backend ({@link com.oracle.max.graal.compiler.target.amd64.AMD64Backend}, {@link com.oracle.max.graal.compiler.target.amd64.AMD64LIRGenerator}, {@link com.oracle.max.graal.compiler.target.amd64.AMD64LIRAssembler}, etc).
  • + * + *
  • + * XIR for safepoints. The C1X backend should use XIR to get the code for safepoints, but currently it still uses the + * handwritten logic (currently only compatible with Maxine).
  • + * + *
+ * + *

Untested features

+ * + *
    + * + *
  • + * Reference map for outgoing overflow arguments. If a C1X method calls another method that has overflow arguments, it + * is not clear if the outgoing overflow argument area, which may contain references, has the appropriate bits set in + * the reference map for the C1X method's frame. Such arguments may be live in the called method.
  • + * + *
  • + * Although it should work, inlining synchronized methods or methods with exception handlers hasn't been tested.
  • + *
  • + * On-stack replacement. C1X retains all of the special logic for performing an OSR compilation. This is basically a + * compilation with a second entrypoint for entry from the interpreter. However, the generation of a runtime-specific + * entry sequence was never tested.
  • + * + *
  • + * {@link com.oracle.max.graal.compiler.C1XIntrinsic Intrinsification} is the mechanism by which the compiler recognizes calls to special JDK or + * runtime methods and replaces them with custom code. It is enabled by the {@link com.oracle.max.graal.compiler.C1XOptions#OptIntrinsify} compiler + * option. The C1X backend has never been tested with intrinsified arithmetic or floating point operations. For best + * performance, it should generate specialized machine code for arithmetic and floating point, perhaps using global + * stubs for complex floating point operations.
    + * Note: Folding of special intrinsified methods is supported, tested, and working. The runtime system may + * register methods to be folded by using the + * {@link com.oracle.max.graal.compiler.C1XIntrinsic#registerFoldableMethod(RiMethod, java.lang.reflect.Method)} call. When the compiler encounters a + * call to such a registered method where the parameters are all constants, it invokes the supplied method with + * reflection. If the reflective call produces a value and does not throw an exception, C1X replaces the call to the + * method with the result.
  • + *
+ * + *

Broken features

+ * + *
    + *
  • + * {@link com.oracle.max.graal.compiler.opt.LoopPeeler Loop peeling} was written by Marcelo Cintra near the end of his internship. It was never completed + * and should be considered broken. It only remains as a sketch of how loop peeling would be implemented in C1X, or in + * case he would finish the implementation and test it.
  • + * + *
  • + * Calls to global stubs should allocate space on the caller's stack. On AMD64 currently, calls to global stubs poke the + * arguments onto the stack below the RSP (i.e. in the callee's stack). While normally this code sequence is + * uninterruptible and works fine in the VM, signal handlers triggered when debugging or inspecting this code sequence + * may destroy these values when the OS calls the signal handler. This requires knowing which global stubs are called + * before finalizing the frame size; currently only the calls to + * {@link com.oracle.max.graal.compiler.target.amd64.AMD64MacroAssembler#callRuntimeCalleeSaved} + * do not fit this pattern. This needs to be fixed so that all global stubs that are called by the assembled code are + * known before beginning assembling. The {@link com.oracle.max.graal.compiler.target.amd64.AMD64GlobalStubEmitter} controls how the global stubs accept their + * parameters. See {@link com.oracle.max.graal.compiler.target.amd64.AMD64GlobalStubEmitter#callerFrameContainsArguments} and its usages. + * + *
  • + *
+ */ +package com.oracle.max.graal.compiler; diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/schedule/Block.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/schedule/Block.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.schedule; + +import java.util.*; + +import com.oracle.max.graal.compiler.ir.*; +import com.oracle.max.graal.graph.*; + + +public class Block { + + private int blockID; + private final List successors = new ArrayList(); + private final List predecessors = new ArrayList(); + private List instructions = new ArrayList(); + private Block dominator; + private final List dominators = new ArrayList(); + + private Node firstNode; + private Node lastNode; + + public Node firstNode() { + return firstNode; + } + + public void setFirstNode(Node node) { + this.firstNode = node; + } + + public Node lastNode() { + return lastNode; + } + + public void setLastNode(Node node) { + this.lastNode = node; + } + + public List getSuccessors() { + return Collections.unmodifiableList(successors); + } + + public void setDominator(Block dominator) { + assert this.dominator == null; + assert dominator != null; + this.dominator = dominator; + dominator.dominators.add(this); + } + + public List getDominators() { + return Collections.unmodifiableList(dominators); + } + + public List getInstructions() { + return instructions; + } + + public List getPredecessors() { + return Collections.unmodifiableList(predecessors); + } + + public Block(int blockID) { + this.blockID = blockID; + } + + public void addSuccessor(Block other) { + successors.add(other); + other.predecessors.add(this); + } + + public int blockID() { + return blockID; + } + + /** + * Iterate over this block, its exception handlers, and its successors, in that order. + * + * @param closure the closure to apply to each block + */ + public void iteratePreOrder(BlockClosure closure) { + // XXX: identity hash map might be too slow, consider a boolean array or a mark field + iterate(new IdentityHashMap(), closure); + } + + private void iterate(IdentityHashMap mark, BlockClosure closure) { + if (!mark.containsKey(this)) { + mark.put(this, this); + closure.apply(this); + + iterateReverse(mark, closure, this.successors); + } + } + + private void iterateReverse(IdentityHashMap mark, BlockClosure closure, List list) { + for (int i = list.size() - 1; i >= 0; i--) { + list.get(i).iterate(mark, closure); + } + } + + @Override + public String toString() { + return "B" + blockID; + } + + public Block dominator() { + return dominator; + } + + public void setInstructions(List instructions) { + this.instructions = instructions; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/schedule/Schedule.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/schedule/Schedule.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,463 @@ +/* + * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.schedule; + +import java.util.*; + +import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.compiler.ir.*; +import com.oracle.max.graal.compiler.value.*; +import com.oracle.max.graal.graph.*; +import com.sun.cri.ci.*; + + +public class Schedule { + private final List blocks = new ArrayList(); + private final NodeMap nodeToBlock; + private final Graph graph; + + public Schedule(Graph graph) { + this.graph = graph; + nodeToBlock = graph.createNodeMap(); + identifyBlocks(); + } + public List getBlocks() { + return Collections.unmodifiableList(blocks); + } + + public NodeMap getNodeToBlock() { + return nodeToBlock; + } + + private Block createBlock() { + Block b = new Block(blocks.size()); + blocks.add(b); + return b; + } + + private Block assignBlock(Node n) { + Block curBlock = nodeToBlock.get(n); + if (curBlock == null) { + curBlock = createBlock(); + return assignBlock(n, curBlock); + } + return curBlock; + } + + + private Block assignBlock(Node n, Block b) { + assert nodeToBlock.get(n) == null; + nodeToBlock.set(n, b); + if (b.firstNode() == null) { + b.setFirstNode(n); + b.setLastNode(n); + } else { + if (b.lastNode() != null) { + b.getInstructions().add(b.lastNode()); + } + b.setLastNode(n); + } + b.setLastNode(n); + return b; + } + + public static boolean isFixed(Node n) { + return n != null && ((n instanceof FixedNode) || n == n.graph().start()); + } + + public static boolean isBlockEnd(Node n) { + return trueSuccessorCount(n) > 1 || n instanceof Anchor || n instanceof Return || n instanceof Unwind; + } + + private void identifyBlocks() { + // Identify blocks. + final ArrayList blockBeginNodes = new ArrayList(); + NodeIterator.iterate(EdgeType.SUCCESSORS, graph.start(), null, new NodeVisitor() { + @Override + public boolean visit(Node n) { + if (!isFixed(n)) { + return false; + } + + if (n instanceof LoopBegin) { + // a LoopBegin is always a merge + assignBlock(n); + blockBeginNodes.add(n); + return true; + } + + Node singlePred = null; + for (Node pred : n.predecessors()) { + if (isFixed(pred)) { + if (singlePred == null) { + singlePred = pred; + } else { + // We have more than one predecessor => we are a merge block. + assignBlock(n); + blockBeginNodes.add(n); + return true; + } + } + } + + if (singlePred == null) { + // We have no predecessor => we are the start block. + assignBlock(n); + blockBeginNodes.add(n); + } else { + // We have a single predecessor => check its successor count. + if (isBlockEnd(singlePred)) { + Block b = assignBlock(n); + blockBeginNodes.add(n); + } else { + assignBlock(n, nodeToBlock.get(singlePred)); + } + } + return true; + }} + ); + + // Connect blocks. + for (Node n : blockBeginNodes) { + Block block = nodeToBlock.get(n); + for (Node pred : n.predecessors()) { + if (isFixed(pred)) { + Block predBlock = nodeToBlock.get(pred); + predBlock.addSuccessor(block); + } + } + + if (n instanceof Merge) { + for (Node usage : n.usages()) { + if (usage instanceof Phi) { + nodeToBlock.set(usage, block); + } + } + } + } + + for (Node n : graph.getNodes()) { + if (n instanceof FrameState) { + FrameState f = (FrameState) n; + if (f.predecessors().size() == 1) { + Block predBlock = nodeToBlock.get(f.predecessors().get(0)); + assert predBlock != null; + nodeToBlock.set(f, predBlock); + predBlock.getInstructions().add(f); + } else { + assert f.predecessors().size() == 0; + } + } + } + + computeDominators(); + + + + // Add successors of loop end nodes. Makes the graph cyclic. + for (Node n : blockBeginNodes) { + Block block = nodeToBlock.get(n); + if (n instanceof LoopBegin) { + LoopBegin loopBegin = (LoopBegin) n; + nodeToBlock.get(loopBegin.loopEnd()).addSuccessor(block); + } + } + + assignLatestPossibleBlockToNodes(); + sortNodesWithinBlocks(); + + //print(); + } + + private void assignLatestPossibleBlockToNodes() { + for (Node n : graph.getNodes()) { + assignLatestPossibleBlockToNode(n); + } + } + + private Block assignLatestPossibleBlockToNode(Node n) { + if (n == null) { + return null; + } + + Block prevBlock = nodeToBlock.get(n); + if (prevBlock != null) { + return prevBlock; + } + + Block block = null; + for (Node succ : n.successors()) { + block = getCommonDominator(block, assignLatestPossibleBlockToNode(succ)); + } + for (Node usage : n.usages()) { + if (usage instanceof Phi) { + Phi phi = (Phi) usage; + Merge merge = phi.block(); + Block mergeBlock = nodeToBlock.get(merge); + assert mergeBlock != null; + for (int i = 0; i < phi.valueCount(); ++i) { + if (phi.valueAt(i) == n) { + if (mergeBlock.getPredecessors().size() == 0) { + TTY.println(merge.toString()); + TTY.println(phi.toString()); + TTY.println(merge.predecessors().toString()); + TTY.println("value count: " + phi.valueCount()); + } + block = getCommonDominator(block, mergeBlock.getPredecessors().get(i)); + } + } + } else if (usage instanceof FrameState && ((FrameState) usage).block() != null) { + Merge merge = ((FrameState) usage).block(); + for (Node pred : merge.predecessors()) { + if (isFixed(pred)) { + block = getCommonDominator(block, nodeToBlock.get(pred)); + } + } + } else { + block = getCommonDominator(block, assignLatestPossibleBlockToNode(usage)); + } + } + + nodeToBlock.set(n, block); + if (block != null) { + block.getInstructions().add(n); + } + return block; + } + + private Block getCommonDominator(Block a, Block b) { + if (a == null) { + return b; + } + if (b == null) { + return a; + } + return commonDominator(a, b); + } + + private void sortNodesWithinBlocks() { + NodeBitMap map = graph.createNodeBitMap(); + for (Block b : blocks) { + sortNodesWithinBlocks(b, map); + } + } + + private void sortNodesWithinBlocks(Block b, NodeBitMap map) { + List instructions = b.getInstructions(); + List sortedInstructions = new ArrayList(); + assert !map.isMarked(b.firstNode()) && nodeToBlock.get(b.firstNode()) == b; + + boolean scheduleFirst = true; + + if (b.firstNode() == b.lastNode()) { + Node node = b.firstNode(); + if (!(node instanceof Merge)) { + scheduleFirst = false; + } + } + if (scheduleFirst) { + addToSorting(b, b.firstNode(), sortedInstructions, map); + } + for (Node i : instructions) { + addToSorting(b, i, sortedInstructions, map); + } + addToSorting(b, b.lastNode(), sortedInstructions, map); + //assert b.firstNode() == sortedInstructions.get(0) : b.firstNode(); + // assert b.lastNode() == sortedInstructions.get(sortedInstructions.size() - 1); + b.setInstructions(sortedInstructions); +// TTY.println("Block " + b); +// for (Node n : sortedInstructions) { +// TTY.println("Node: " + n); +// } + } + + private void addToSorting(Block b, Node i, List sortedInstructions, NodeBitMap map) { + if (i == null || map.isMarked(i) || nodeToBlock.get(i) != b || i instanceof Phi || i instanceof Local) { + return; + } + + for (Node input : i.inputs()) { + addToSorting(b, input, sortedInstructions, map); + } + + for (Node pred : i.predecessors()) { + addToSorting(b, pred, sortedInstructions, map); + } + + map.mark(i); + + for (Node succ : i.successors()) { + if (succ instanceof FrameState) { + addToSorting(b, succ, sortedInstructions, map); + } + } + + // Now predecessors and inputs are scheduled => we can add this node. + if (!(i instanceof FrameState)) { + sortedInstructions.add(i); + } + } + + private void computeDominators() { + Block dominatorRoot = nodeToBlock.get(graph.start()); + assert dominatorRoot.getPredecessors().size() == 0; + CiBitMap visited = new CiBitMap(blocks.size()); + visited.set(dominatorRoot.blockID()); + LinkedList workList = new LinkedList(); + workList.add(dominatorRoot); + + while (!workList.isEmpty()) { + Block b = workList.remove(); + + List predecessors = b.getPredecessors(); + if (predecessors.size() == 1) { + b.setDominator(predecessors.get(0)); + } else if (predecessors.size() > 0) { + boolean delay = false; + for (Block pred : predecessors) { + if (pred != dominatorRoot && pred.dominator() == null) { + delay = true; + break; + } + } + + if (delay) { + workList.add(b); + continue; + } + + Block dominator = null; + for (Block pred : predecessors) { + if (dominator == null) { + dominator = pred; + } else { + dominator = commonDominator(dominator, pred); + } + } + b.setDominator(dominator); + } + + for (Block succ : b.getSuccessors()) { + if (!visited.get(succ.blockID())) { + visited.set(succ.blockID()); + workList.add(succ); + } + } + } + } + + public Block commonDominator(Block a, Block b) { + CiBitMap bitMap = new CiBitMap(blocks.size()); + Block cur = a; + while (cur != null) { + bitMap.set(cur.blockID()); + cur = cur.dominator(); + } + + cur = b; + while (cur != null) { + if (bitMap.get(cur.blockID())) { + return cur; + } + cur = cur.dominator(); + } + + print(); + assert false : "no common dominator between " + a + " and " + b; + return null; + } + + private void print() { + TTY.println("============================================"); + TTY.println("%d blocks", blocks.size()); + + for (Block b : blocks) { + TTY.println(); + TTY.print(b.toString()); + + TTY.print(" succs="); + for (Block succ : b.getSuccessors()) { + TTY.print(succ + ";"); + } + + TTY.print(" preds="); + for (Block pred : b.getPredecessors()) { + TTY.print(pred + ";"); + } + + if (b.dominator() != null) { + TTY.print(" dom=" + b.dominator()); + } + TTY.println(); + + if (b.getInstructions().size() > 0) { + TTY.print("first instr: " + b.getInstructions().get(0)); + TTY.print("last instr: " + b.getInstructions().get(b.getInstructions().size() - 1)); + } + } + +/* + TTY.println("============================================"); + TTY.println("%d nodes", nodeToBlock.size()); + for (Node n : graph.getNodes()) { + if (n != null) { + TTY.print("Node %d: %s", n.id(), n.getClass().toString()); + Block curBlock = nodeToBlock.get(n); + if (curBlock != null) { + TTY.print(" %s", curBlock); + } + TTY.println(); + } + }*/ + } + + public static int trueSuccessorCount(Node n) { + if (n == null) { + return 0; + } + int i = 0; + for (Node s : n.successors()) { + if (isFixed(s)) { + i++; + } + } + return i; + } + + public static int truePredecessorCount(Node n) { + if (n == null) { + return 0; + } + int i = 0; + for (Node s : n.predecessors()) { + if (isFixed(s)) { + i++; + } + } + + if (n instanceof LoopBegin) { + i++; + } + return i; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/Backend.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/Backend.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.target; + +import java.lang.reflect.*; + +import com.oracle.max.asm.*; +import com.oracle.max.graal.compiler.*; +import com.oracle.max.graal.compiler.gen.*; +import com.oracle.max.graal.compiler.globalstub.*; +import com.oracle.max.graal.compiler.lir.*; +import com.sun.cri.ci.*; +import com.sun.cri.ri.*; +import com.sun.cri.xir.*; + +/** + * The {@code Backend} class represents a compiler backend for C1X. + * + * @author Ben L. Titzer + */ +public abstract class Backend { + public final C1XCompiler compiler; + + protected Backend(C1XCompiler compiler) { + this.compiler = compiler; + } + + public static Backend create(CiArchitecture arch, C1XCompiler compiler) { + String className = arch.getClass().getName().replace("com.oracle.max.asm", "com.oracle.max.graal.compiler") + "Backend"; + try { + Class c = Class.forName(className); + Constructor cons = c.getDeclaredConstructor(C1XCompiler.class); + return (Backend) cons.newInstance(compiler); + } catch (Exception e) { + throw new Error("Could not instantiate " + className, e); + } + } + + public abstract FrameMap newFrameMap(RiMethod method, int numberOfLocks); + public abstract LIRGenerator newLIRGenerator(C1XCompilation compilation); + public abstract LIRAssembler newLIRAssembler(C1XCompilation compilation); + public abstract AbstractAssembler newAssembler(RiRegisterConfig registerConfig); + public abstract GlobalStubEmitter newGlobalStubEmitter(); + public abstract CiXirAssembler newXirAssembler(); +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64Backend.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64Backend.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.target.amd64; + +import static com.oracle.max.graal.compiler.C1XCompilation.*; + +import com.oracle.max.asm.*; +import com.oracle.max.asm.target.amd64.*; +import com.oracle.max.graal.compiler.*; +import com.oracle.max.graal.compiler.gen.*; +import com.oracle.max.graal.compiler.globalstub.*; +import com.oracle.max.graal.compiler.lir.*; +import com.oracle.max.graal.compiler.target.*; +import com.sun.cri.ri.*; +import com.sun.cri.xir.*; + +/** + * The {@code X86Backend} class represents the backend for the AMD64 architecture. + * + * @author Ben L. Titzer + */ +public class AMD64Backend extends Backend { + + public AMD64Backend(C1XCompiler compiler) { + super(compiler); + } + /** + * Creates a new LIRGenerator for x86. + * @param compilation the compilation for which to create the LIR generator + * @return an appropriate LIR generator instance + */ + @Override + public LIRGenerator newLIRGenerator(C1XCompilation compilation) { + return new AMD64LIRGenerator(compilation); + } + + /** + * Creates a new LIRAssembler for x86. + * @param compilation the compilation for which to create the LIR assembler + * @return an appropriate LIR assembler instance + */ + @Override + public LIRAssembler newLIRAssembler(C1XCompilation compilation) { + return new AMD64LIRAssembler(compilation); + } + + @Override + public FrameMap newFrameMap(RiMethod method, int numberOfLocks) { + return new FrameMap(compilation(), method, numberOfLocks); + } + @Override + public AbstractAssembler newAssembler(RiRegisterConfig registerConfig) { + return new AMD64MacroAssembler(compiler.target, registerConfig); + } + + @Override + public CiXirAssembler newXirAssembler() { + return new AMD64XirAssembler(); + } + + @Override + public GlobalStubEmitter newGlobalStubEmitter() { + return new AMD64GlobalStubEmitter(compiler); + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64GlobalStubEmitter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64GlobalStubEmitter.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,439 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.target.amd64; + +import static com.sun.cri.ci.CiCallingConvention.Type.*; + +import java.util.*; + +import com.oracle.max.asm.*; +import com.oracle.max.asm.target.amd64.*; +import com.oracle.max.asm.target.amd64.AMD64Assembler.*; +import com.oracle.max.graal.compiler.*; +import com.oracle.max.graal.compiler.asm.*; +import com.oracle.max.graal.compiler.globalstub.*; +import com.sun.cri.ci.*; +import com.sun.cri.ci.CiRegister.*; +import com.sun.cri.ri.*; +import com.sun.cri.xir.*; +import com.sun.cri.xir.CiXirAssembler.*; + +public class AMD64GlobalStubEmitter implements GlobalStubEmitter { + + public static final int ARGUMENT_SIZE = 8; + + private static final long FloatSignFlip = 0x8000000080000000L; + private static final long DoubleSignFlip = 0x8000000000000000L; + private static final CiRegister convertArgument = AMD64.xmm0; + private static final CiRegister convertResult = AMD64.rax; + private static final CiRegister negateArgument = AMD64.xmm0; + private static final CiRegister negateTemp = AMD64.xmm1; + + private TargetMethodAssembler tasm; + private AMD64MacroAssembler asm; + private final CiTarget target; + private int argsSize; + private int[] argOffsets; + private int resultOffset; + private int saveSize; + private int registerRestoreEpilogueOffset; + + private RiRuntime runtime; + private C1XCompiler compiler; + private CiRegister[] registersSaved; + + private boolean savedAllRegisters; + + public AMD64GlobalStubEmitter(C1XCompiler compiler) { + this.compiler = compiler; + this.target = compiler.target; + this.runtime = compiler.runtime; + } + + private void reset(CiKind resultKind, CiKind[] argTypes) { + asm = new AMD64MacroAssembler(compiler.target, compiler.globalStubRegisterConfig); + tasm = new TargetMethodAssembler(asm); + saveSize = 0; + argsSize = 0; + argOffsets = new int[argTypes.length]; + resultOffset = 0; + registerRestoreEpilogueOffset = -1; + registersSaved = null; + + for (int i = 0; i < argTypes.length; i++) { + argOffsets[i] = argsSize; + argsSize += ARGUMENT_SIZE; + } + + if (resultKind != CiKind.Void) { + if (argsSize == 0) { + argsSize = ARGUMENT_SIZE; + } + resultOffset = 0; + } + } + + public GlobalStub emit(CiRuntimeCall runtimeCall, RiRuntime runtime) { + reset(runtimeCall.resultKind, runtimeCall.arguments); + emitStandardForward(null, runtimeCall); + String name = "stub-" + runtimeCall; + CiTargetMethod targetMethod = tasm.finishTargetMethod(name, runtime, registerRestoreEpilogueOffset, true); + Object stubObject = runtime.registerGlobalStub(targetMethod, name); + return new GlobalStub(null, runtimeCall.resultKind, stubObject, argsSize, argOffsets, resultOffset); + } + + public GlobalStub emit(GlobalStub.Id stub, RiRuntime runtime) { + reset(stub.resultKind, stub.arguments); + + switch (stub) { + case f2i: + emitF2I(); + break; + case f2l: + emitF2L(); + break; + case d2i: + emitD2I(); + break; + case d2l: + emitD2L(); + break; + case fneg: + emitFNEG(); + break; + case dneg: + emitDNEG(); + break; + } + + String name = "stub-" + stub; + CiTargetMethod targetMethod = tasm.finishTargetMethod(name, runtime, registerRestoreEpilogueOffset, true); + Object stubObject = runtime.registerGlobalStub(targetMethod, name); + return new GlobalStub(stub, stub.resultKind, stubObject, argsSize, argOffsets, resultOffset); + } + + private CiValue allocateParameterOperand(XirParameter param, int parameterIndex) { + return new CiAddress(param.kind, AMD64.RSP, argumentIndexToStackOffset(parameterIndex)); + } + + private CiValue allocateResultOperand(XirOperand result) { + return new CiAddress(result.kind, AMD64.RSP, argumentIndexToStackOffset(0)); + } + + private CiValue allocateOperand(XirTemp temp, ArrayList allocatableRegisters) { + if (temp instanceof XirRegister) { + XirRegister fixed = (XirRegister) temp; + return fixed.register; + } + + return newRegister(temp.kind, allocatableRegisters); + } + + private CiValue newRegister(CiKind kind, ArrayList allocatableRegisters) { + assert kind != CiKind.Float && kind != CiKind.Double; + assert allocatableRegisters.size() > 0; + return allocatableRegisters.remove(allocatableRegisters.size() - 1).asValue(kind); + } + + public GlobalStub emit(XirTemplate template, RiRuntime runtime) { + C1XCompilation compilation = new C1XCompilation(compiler, null, -1, null); + try { + return emit(template, compilation); + } finally { + compilation.close(); + } + } + + public GlobalStub emit(XirTemplate template, C1XCompilation compilation) { + reset(template.resultOperand.kind, getArgumentKinds(template)); + compilation.initFrameMap(0); + compilation.frameMap().setFrameSize(frameSize()); + AMD64LIRAssembler assembler = new AMD64LIRAssembler(compilation); + asm = assembler.masm; + tasm = assembler.tasm; + + ArrayList allocatableRegisters = new ArrayList(Arrays.asList(compiler.globalStubRegisterConfig.getCategorizedAllocatableRegisters().get(RegisterFlag.CPU))); + for (XirTemp t : template.temps) { + if (t instanceof XirRegister) { + final XirRegister fixed = (XirRegister) t; + if (fixed.register.isRegister()) { + allocatableRegisters.remove(fixed.register.asRegister()); + } + } + } + + completeSavePrologue(); + + CiValue[] operands = new CiValue[template.variableCount]; + + XirOperand resultOperand = template.resultOperand; + + if (template.allocateResultOperand) { + CiValue outputOperand = CiValue.IllegalValue; + // This snippet has a result that must be separately allocated + // Otherwise it is assumed that the result is part of the inputs + if (resultOperand.kind != CiKind.Void && resultOperand.kind != CiKind.Illegal) { + outputOperand = allocateResultOperand(resultOperand); + assert operands[resultOperand.index] == null; + } + operands[resultOperand.index] = outputOperand; + } + + for (XirParameter param : template.parameters) { + assert !(param instanceof XirConstantOperand) : "constant parameters not supported for stubs"; + CiValue op = allocateParameterOperand(param, param.parameterIndex); + assert operands[param.index] == null; + + // Is the value destroyed? + if (template.isParameterDestroyed(param.parameterIndex)) { + CiValue newOp = newRegister(op.kind, allocatableRegisters); + assembler.moveOp(op, newOp, op.kind, null, false); + operands[param.index] = newOp; + } else { + operands[param.index] = op; + } + } + + for (XirConstant c : template.constants) { + assert operands[c.index] == null; + operands[c.index] = c.value; + } + + for (XirTemp t : template.temps) { + CiValue op = allocateOperand(t, allocatableRegisters); + assert operands[t.index] == null; + operands[t.index] = op; + } + + for (CiValue operand : operands) { + assert operand != null; + } + + Label[] labels = new Label[template.labels.length]; + for (int i = 0; i < labels.length; i++) { + labels[i] = new Label(); + } + + assert template.marks.length == 0 : "marks not supported in global stubs"; + assembler.emitXirInstructions(null, template.fastPath, labels, operands, null); + epilogue(); + CiTargetMethod targetMethod = tasm.finishTargetMethod(template.name, runtime, registerRestoreEpilogueOffset, true); + Object stubObject = runtime.registerGlobalStub(targetMethod, template.name); + return new GlobalStub(null, template.resultOperand.kind, stubObject, argsSize, argOffsets, resultOffset); + } + + private CiKind[] getArgumentKinds(XirTemplate template) { + CiXirAssembler.XirParameter[] params = template.parameters; + CiKind[] result = new CiKind[params.length]; + for (int i = 0; i < params.length; i++) { + result[i] = params[i].kind; + } + return result; + } + + private void negatePrologue() { + partialSavePrologue(negateArgument, negateTemp); + loadArgument(0, negateArgument); + } + + private void negateEpilogue() { + storeArgument(0, negateArgument); + epilogue(); + } + + private void emitDNEG() { + negatePrologue(); + asm.movsd(negateTemp, tasm.recordDataReferenceInCode(CiConstant.forLong(DoubleSignFlip))); + asm.xorpd(negateArgument, negateTemp); + negateEpilogue(); + } + + private void emitFNEG() { + negatePrologue(); + asm.movsd(negateTemp, tasm.recordDataReferenceInCode(CiConstant.forLong(FloatSignFlip))); + asm.xorps(negateArgument, negateTemp); + negateEpilogue(); + } + + private void convertPrologue() { + partialSavePrologue(convertArgument, convertResult); + loadArgument(0, convertArgument); + } + + private void convertEpilogue() { + storeArgument(0, convertResult); + epilogue(); + } + + private void emitD2L() { + emitCOMISSD(true, false); + } + + private void emitD2I() { + emitCOMISSD(true, true); + } + + private void emitF2L() { + emitCOMISSD(false, false); + } + + private void emitF2I() { + emitCOMISSD(false, true); + } + + private void emitCOMISSD(boolean isDouble, boolean isInt) { + convertPrologue(); + if (isDouble) { + asm.ucomisd(convertArgument, tasm.recordDataReferenceInCode(CiConstant.DOUBLE_0)); + } else { + asm.ucomiss(convertArgument, tasm.recordDataReferenceInCode(CiConstant.FLOAT_0)); + } + Label nan = new Label(); + Label ret = new Label(); + asm.jccb(ConditionFlag.parity, nan); + asm.jccb(ConditionFlag.below, ret); + + // input is > 0 -> return maxInt + // result register already contains 0x80000000, so subtracting 1 gives 0x7fffffff + asm.decrementl(convertResult, 1); + asm.jmpb(ret); + + // input is NaN -> return 0 + asm.bind(nan); + asm.xorptr(convertResult, convertResult); + + asm.bind(ret); + convertEpilogue(); + } + + private void emitStandardForward(GlobalStub.Id stub, CiRuntimeCall call) { + if (stub != null) { + assert stub.resultKind == call.resultKind; + assert stub.arguments.length == call.arguments.length; + for (int i = 0; i < stub.arguments.length; i++) { + assert stub.arguments[i] == call.arguments[i]; + } + } + + completeSavePrologue(); + forwardRuntimeCall(call); + epilogue(); + } + + private int argumentIndexToStackOffset(int index) { + // <-- lower addresses + // | stub frame | caller frame | + // | locals,savearea,retaddr | args ..... | + return frameSize() + (index + 1) * ARGUMENT_SIZE; + } + + private void loadArgument(int index, CiRegister register) { + asm.movq(register, new CiAddress(CiKind.Word, AMD64.RSP, argumentIndexToStackOffset(index))); + } + + private void storeArgument(int index, CiRegister register) { + asm.movq(new CiAddress(CiKind.Word, AMD64.RSP, argumentIndexToStackOffset(index)), register); + } + + private void partialSavePrologue(CiRegister... registersToSave) { + this.registersSaved = registersToSave; + this.saveSize = registersToSave.length * target.wordSize; + + // align to code size + int entryCodeOffset = runtime.codeOffset(); + if (entryCodeOffset != 0) { + asm.nop(entryCodeOffset); + } + asm.subq(AMD64.rsp, frameSize()); + + int index = 0; + for (CiRegister r : registersToSave) { + asm.movq(new CiAddress(CiKind.Word, AMD64.RSP, index * target.arch.wordSize), r); + index++; + } + + tasm.setFrameSize(frameSize()); + this.savedAllRegisters = false; + } + + private void completeSavePrologue() { + CiCalleeSaveArea csa = compiler.globalStubRegisterConfig.getCalleeSaveArea(); + this.saveSize = csa.size; + int entryCodeOffset = runtime.codeOffset(); + if (entryCodeOffset != 0) { + // align to code size + asm.nop(entryCodeOffset); + } + asm.subq(AMD64.rsp, frameSize()); + tasm.setFrameSize(frameSize()); + int frameToCSA = 0; + asm.save(csa, frameToCSA); + this.savedAllRegisters = true; + } + + private void epilogue() { + assert registerRestoreEpilogueOffset == -1; + registerRestoreEpilogueOffset = asm.codeBuffer.position(); + + if (savedAllRegisters) { + CiCalleeSaveArea csa = compiler.globalStubRegisterConfig.getCalleeSaveArea(); + int frameToCSA = 0; + asm.restore(csa, frameToCSA); + } else { + // saved only select registers + for (int index = 0; index < registersSaved.length; index++) { + CiRegister r = registersSaved[index]; + asm.movq(r, new CiAddress(CiKind.Word, AMD64.RSP, index * target.wordSize)); + } + registersSaved = null; + } + + // Restore rsp + asm.addq(AMD64.rsp, frameSize()); + asm.ret(0); + } + + private int frameSize() { + return target.alignFrameSize(saveSize); + } + + private void forwardRuntimeCall(CiRuntimeCall call) { + // Load arguments + CiCallingConvention cc = compiler.globalStubRegisterConfig.getCallingConvention(RuntimeCall, call.arguments, target); + for (int i = 0; i < cc.locations.length; ++i) { + CiValue location = cc.locations[i]; + loadArgument(i, location.asRegister()); + } + + // Call to the runtime + int before = asm.codeBuffer.position(); + asm.call(); + int after = asm.codeBuffer.position(); + tasm.recordDirectCall(before, after, call, null); + + if (call.resultKind != CiKind.Void) { + CiRegister returnRegister = compiler.globalStubRegisterConfig.getReturnRegister(call.resultKind); + this.storeArgument(0, returnRegister); + } + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64LIRAssembler.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64LIRAssembler.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,2197 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.target.amd64; + +import static com.sun.cri.bytecode.Bytecodes.*; +import static com.sun.cri.ci.CiCallingConvention.Type.*; +import static com.sun.cri.ci.CiRegister.*; +import static com.sun.cri.ci.CiValue.*; +import static java.lang.Double.*; +import static java.lang.Float.*; + +import java.util.*; + +import com.oracle.max.asm.*; +import com.oracle.max.asm.target.amd64.*; +import com.oracle.max.asm.target.amd64.AMD64Assembler.*; +import com.oracle.max.graal.compiler.*; +import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.compiler.gen.LIRGenerator.*; +import com.oracle.max.graal.compiler.globalstub.*; +import com.oracle.max.graal.compiler.ir.*; +import com.oracle.max.graal.compiler.lir.*; +import com.oracle.max.graal.compiler.lir.FrameMap.*; +import com.oracle.max.graal.compiler.util.*; +import com.sun.cri.ci.*; +import com.sun.cri.ci.CiAddress.*; +import com.sun.cri.ci.CiTargetMethod.*; +import com.sun.cri.xir.*; +import com.sun.cri.xir.CiXirAssembler.*; + +/** + * This class implements the x86-specific code generation for LIR. + */ +public final class AMD64LIRAssembler extends LIRAssembler { + + private static final Object[] NO_PARAMS = new Object[0]; + private static final long NULLWORD = 0; + private static final CiRegister SHIFTCount = AMD64.rcx; + + private static final long DoubleSignMask = 0x7FFFFFFFFFFFFFFFL; + + final CiTarget target; + final AMD64MacroAssembler masm; + final int wordSize; + final CiRegister rscratch1; + + public AMD64LIRAssembler(C1XCompilation compilation) { + super(compilation); + masm = (AMD64MacroAssembler) asm; + target = compilation.target; + wordSize = target.wordSize; + rscratch1 = compilation.registerConfig.getScratchRegister(); + } + + private CiAddress asAddress(CiValue value) { + if (value.isAddress()) { + return (CiAddress) value; + } + assert value.isStackSlot(); + return compilation.frameMap().toStackAddress((CiStackSlot) value); + } + + @Override + protected int initialFrameSizeInBytes() { + return frameMap.frameSize(); + } + + @Override + protected void emitReturn(CiValue result) { + // TODO: Consider adding safepoint polling at return! + masm.ret(0); + } + + @Override + protected void emitMonitorAddress(int monitor, CiValue dst) { + CiStackSlot slot = frameMap.toMonitorBaseStackAddress(monitor); + masm.leaq(dst.asRegister(), new CiAddress(slot.kind, AMD64.rsp.asValue(), slot.index() * target.arch.wordSize)); + } + + @Override + protected void emitBreakpoint() { + masm.int3(); + } + + @Override + protected void emitStackAllocate(StackBlock stackBlock, CiValue dst) { + masm.leaq(dst.asRegister(), compilation.frameMap().toStackAddress(stackBlock)); + } + + private void moveRegs(CiRegister fromReg, CiRegister toReg) { + if (fromReg != toReg) { + masm.mov(toReg, fromReg); + } + } + + private void swapReg(CiRegister a, CiRegister b) { + masm.xchgptr(a, b); + } + + private void const2reg(CiRegister dst, int constant) { + // Do not optimize with an XOR as this instruction may be between + // a CMP and a Jcc in which case the XOR will modify the condition + // flags and interfere with the Jcc. + masm.movl(dst, constant); + } + + private void const2reg(CiRegister dst, long constant) { + // Do not optimize with an XOR as this instruction may be between + // a CMP and a Jcc in which case the XOR will modify the condition + // flags and interfere with the Jcc. + masm.movq(dst, constant); + } + + private void const2reg(CiRegister dst, CiConstant constant) { + assert constant.kind == CiKind.Object; + // Do not optimize with an XOR as this instruction may be between + // a CMP and a Jcc in which case the XOR will modify the condition + // flags and interfere with the Jcc. + if (constant.isNull()) { + masm.movq(dst, 0x0L); + } else if (target.inlineObjects) { + tasm.recordDataReferenceInCode(constant); + masm.movq(dst, 0xDEADDEADDEADDEADL); + } else { + masm.movq(dst, tasm.recordDataReferenceInCode(constant)); + } + } + + @Override + public void emitTraps() { + for (int i = 0; i < C1XOptions.MethodEndBreakpointGuards; ++i) { + masm.int3(); + } + } + + private void const2reg(CiRegister dst, float constant) { + if (constant == 0.0f) { + masm.xorps(dst, dst); + } else { + masm.movflt(dst, tasm.recordDataReferenceInCode(CiConstant.forFloat(constant))); + } + } + + private void const2reg(CiRegister dst, double constant) { + if (constant == 0.0f) { + masm.xorpd(dst, dst); + } else { + masm.movdbl(dst, tasm.recordDataReferenceInCode(CiConstant.forDouble(constant))); + } + } + + @Override + protected void const2reg(CiValue src, CiValue dest, LIRDebugInfo info) { + assert src.isConstant(); + assert dest.isRegister(); + CiConstant c = (CiConstant) src; + + // Checkstyle: off + switch (c.kind) { + case Boolean : + case Byte : + case Char : + case Short : + case Jsr : + case Int : const2reg(dest.asRegister(), c.asInt()); break; + case Word : + case Long : const2reg(dest.asRegister(), c.asLong()); break; + case Object : const2reg(dest.asRegister(), c); break; + case Float : const2reg(asXmmFloatReg(dest), c.asFloat()); break; + case Double : const2reg(asXmmDoubleReg(dest), c.asDouble()); break; + default : throw Util.shouldNotReachHere(); + } + // Checkstyle: on + } + + @Override + protected void const2stack(CiValue src, CiValue dst) { + assert src.isConstant(); + assert dst.isStackSlot(); + CiStackSlot slot = (CiStackSlot) dst; + CiConstant c = (CiConstant) src; + + // Checkstyle: off + switch (c.kind) { + case Boolean : + case Byte : + case Char : + case Short : + case Jsr : + case Int : masm.movl(frameMap.toStackAddress(slot), c.asInt()); break; + case Float : masm.movl(frameMap.toStackAddress(slot), floatToRawIntBits(c.asFloat())); break; + case Object : movoop(frameMap.toStackAddress(slot), c); break; + case Long : masm.mov64(frameMap.toStackAddress(slot), c.asLong()); break; + case Double : masm.mov64(frameMap.toStackAddress(slot), doubleToRawLongBits(c.asDouble())); break; + default : throw Util.shouldNotReachHere("Unknown constant kind for const2stack: " + c.kind); + } + // Checkstyle: on + } + + @Override + protected void const2mem(CiValue src, CiValue dst, CiKind kind, LIRDebugInfo info) { + assert src.isConstant(); + assert dst.isAddress(); + CiConstant constant = (CiConstant) src; + CiAddress addr = asAddress(dst); + + int nullCheckHere = codePos(); + // Checkstyle: off + switch (kind) { + case Boolean : + case Byte : masm.movb(addr, constant.asInt() & 0xFF); break; + case Char : + case Short : masm.movw(addr, constant.asInt() & 0xFFFF); break; + case Jsr : + case Int : masm.movl(addr, constant.asInt()); break; + case Float : masm.movl(addr, floatToRawIntBits(constant.asFloat())); break; + case Object : movoop(addr, constant); break; + case Word: + case Long : masm.movq(rscratch1, constant.asLong()); + nullCheckHere = codePos(); + masm.movq(addr, rscratch1); break; + case Double : masm.movq(rscratch1, doubleToRawLongBits(constant.asDouble())); + nullCheckHere = codePos(); + masm.movq(addr, rscratch1); break; + default : throw Util.shouldNotReachHere(); + } + // Checkstyle: on + + if (info != null) { + tasm.recordImplicitException(nullCheckHere, info); + } + } + + @Override + protected void reg2reg(CiValue src, CiValue dest) { + assert src.isRegister(); + assert dest.isRegister(); + + if (dest.kind.isFloat()) { + masm.movflt(asXmmFloatReg(dest), asXmmFloatReg(src)); + } else if (dest.kind.isDouble()) { + masm.movdbl(asXmmDoubleReg(dest), asXmmDoubleReg(src)); + } else { + moveRegs(src.asRegister(), dest.asRegister()); + } + } + + @Override + protected void reg2stack(CiValue src, CiValue dst, CiKind kind) { + assert src.isRegister(); + assert dst.isStackSlot(); + CiAddress addr = frameMap.toStackAddress((CiStackSlot) dst); + + // Checkstyle: off + switch (src.kind) { + case Boolean : + case Byte : + case Char : + case Short : + case Jsr : + case Int : masm.movl(addr, src.asRegister()); break; + case Object : + case Word : + case Long : masm.movq(addr, src.asRegister()); break; + case Float : masm.movflt(addr, asXmmFloatReg(src)); break; + case Double : masm.movsd(addr, asXmmDoubleReg(src)); break; + default : throw Util.shouldNotReachHere(); + } + // Checkstyle: on + } + + @Override + protected void reg2mem(CiValue src, CiValue dest, CiKind kind, LIRDebugInfo info, boolean unaligned) { + CiAddress toAddr = (CiAddress) dest; + + if (info != null) { + tasm.recordImplicitException(codePos(), info); + } + + // Checkstyle: off + switch (kind) { + case Float : masm.movflt(toAddr, asXmmFloatReg(src)); break; + case Double : masm.movsd(toAddr, asXmmDoubleReg(src)); break; + case Jsr : + case Int : masm.movl(toAddr, src.asRegister()); break; + case Long : + case Word : + case Object : masm.movq(toAddr, src.asRegister()); break; + case Char : + case Short : masm.movw(toAddr, src.asRegister()); break; + case Byte : + case Boolean : masm.movb(toAddr, src.asRegister()); break; + default : throw Util.shouldNotReachHere(); + } + // Checkstyle: on + } + + private static CiRegister asXmmFloatReg(CiValue src) { + assert src.kind.isFloat() : "must be float, actual kind: " + src.kind; + CiRegister result = src.asRegister(); + assert result.isFpu() : "must be xmm, actual type: " + result; + return result; + } + + @Override + protected void stack2reg(CiValue src, CiValue dest, CiKind kind) { + assert src.isStackSlot(); + assert dest.isRegister(); + + CiAddress addr = frameMap.toStackAddress((CiStackSlot) src); + + // Checkstyle: off + switch (dest.kind) { + case Boolean : + case Byte : + case Char : + case Short : + case Jsr : + case Int : masm.movl(dest.asRegister(), addr); break; + case Object : + case Word : + case Long : masm.movq(dest.asRegister(), addr); break; + case Float : masm.movflt(asXmmFloatReg(dest), addr); break; + case Double : masm.movdbl(asXmmDoubleReg(dest), addr); break; + default : throw Util.shouldNotReachHere(); + } + // Checkstyle: on + } + + @Override + protected void mem2mem(CiValue src, CiValue dest, CiKind kind) { + if (dest.kind.isInt()) { + masm.pushl((CiAddress) src); + masm.popl((CiAddress) dest); + } else { + masm.pushptr((CiAddress) src); + masm.popptr((CiAddress) dest); + } + } + + @Override + protected void mem2stack(CiValue src, CiValue dest, CiKind kind) { + if (dest.kind.isInt()) { + masm.pushl((CiAddress) src); + masm.popl(frameMap.toStackAddress((CiStackSlot) dest)); + } else { + masm.pushptr((CiAddress) src); + masm.popptr(frameMap.toStackAddress((CiStackSlot) dest)); + } + } + + @Override + protected void stack2stack(CiValue src, CiValue dest, CiKind kind) { + if (src.kind.isInt()) { + masm.pushl(frameMap.toStackAddress((CiStackSlot) src)); + masm.popl(frameMap.toStackAddress((CiStackSlot) dest)); + } else { + masm.pushptr(frameMap.toStackAddress((CiStackSlot) src)); + masm.popptr(frameMap.toStackAddress((CiStackSlot) dest)); + } + } + + @Override + protected void mem2reg(CiValue src, CiValue dest, CiKind kind, LIRDebugInfo info, boolean unaligned) { + assert src.isAddress(); + assert dest.isRegister() : "dest=" + dest; + + CiAddress addr = (CiAddress) src; + if (info != null) { + tasm.recordImplicitException(codePos(), info); + } + + // Checkstyle: off + switch (kind) { + case Float : masm.movflt(asXmmFloatReg(dest), addr); break; + case Double : masm.movdbl(asXmmDoubleReg(dest), addr); break; + case Object : masm.movq(dest.asRegister(), addr); break; + case Int : masm.movslq(dest.asRegister(), addr); break; + case Word : + case Long : masm.movq(dest.asRegister(), addr); break; + case Boolean : + case Byte : masm.movsxb(dest.asRegister(), addr); break; + case Char : masm.movzxl(dest.asRegister(), addr); break; + case Short : masm.movswl(dest.asRegister(), addr); break; + default : throw Util.shouldNotReachHere(); + } + // Checkstyle: on + } + + @Override + protected void emitReadPrefetch(CiValue src) { + CiAddress addr = (CiAddress) src; + // Checkstyle: off + switch (C1XOptions.ReadPrefetchInstr) { + case 0 : masm.prefetchnta(addr); break; + case 1 : masm.prefetcht0(addr); break; + case 2 : masm.prefetcht2(addr); break; + default : throw Util.shouldNotReachHere(); + } + // Checkstyle: on + } + + @Override + protected void emitOp3(LIROp3 op) { + // Checkstyle: off + switch (op.code) { + case Idiv : + case Irem : arithmeticIdiv(op.code, op.opr1(), op.opr2(), op.result(), op.info); break; + case Ldiv : + case Lrem : arithmeticLdiv(op.code, op.opr1(), op.opr2(), op.result(), op.info); break; + case Wdiv : + case Wdivi : + case Wrem : + case Wremi : arithmeticWdiv(op.code, op.opr1(), op.opr2(), op.result(), op.info); break; + default : throw Util.shouldNotReachHere(); + } + // Checkstyle: on + } + + private boolean assertEmitBranch(LIRBranch op) { + assert op.block() == null || op.block().label() == op.label() : "wrong label"; + if (op.block() != null) { + branchTargetBlocks.add(op.block()); + } + if (op.unorderedBlock() != null) { + branchTargetBlocks.add(op.unorderedBlock()); + } + return true; + } + + private boolean assertEmitTableSwitch(LIRTableSwitch op) { + assert op.defaultTarget != null; + branchTargetBlocks.add(op.defaultTarget); + for (LIRBlock target : op.targets) { + assert target != null; + branchTargetBlocks.add(target); + } + return true; + } + + @Override + protected void emitTableSwitch(LIRTableSwitch op) { + + assert assertEmitTableSwitch(op); + + CiRegister value = op.value().asRegister(); + final Buffer buf = masm.codeBuffer; + + // Compare index against jump table bounds + int highKey = op.lowKey + op.targets.length - 1; + if (op.lowKey != 0) { + // subtract the low value from the switch value + masm.subl(value, op.lowKey); + masm.cmpl(value, highKey - op.lowKey); + } else { + masm.cmpl(value, highKey); + } + + // Jump to default target if index is not within the jump table + masm.jcc(ConditionFlag.above, op.defaultTarget.label()); + + // Set scratch to address of jump table + int leaPos = buf.position(); + buf.putMark(); + masm.leaq(rscratch1, new CiAddress(CiKind.Word, InstructionRelative.asValue(), 0)); + + // Load jump table entry into scratch and jump to it + masm.movslq(value, new CiAddress(CiKind.Int, rscratch1.asValue(), value.asValue(), Scale.Times4, 0)); + masm.addq(rscratch1, value); + masm.jmp(rscratch1); + + // Inserting padding so that jump table address is 4-byte aligned + if ((buf.position() & 0x3) != 0) { + masm.nop(4 - (buf.position() & 0x3)); + } + + // Patch LEA instruction above now that we know the position of the jump table + int jumpTablePos = buf.position(); + buf.setPosition(leaPos); + buf.putMark(); + masm.leaq(rscratch1, new CiAddress(CiKind.Word, InstructionRelative.asValue(), jumpTablePos - leaPos)); + buf.setPosition(jumpTablePos); + + // Emit jump table entries + for (LIRBlock target : op.targets) { + Label label = target.label(); + int offsetToJumpTableBase = buf.position() - jumpTablePos; + if (label.isBound()) { + int imm32 = label.position() - jumpTablePos; + buf.emitInt(imm32); + } else { + label.addPatchAt(buf.position()); + + buf.emitByte(0); // psuedo-opcode for jump table entry + buf.emitShort(offsetToJumpTableBase); + buf.emitByte(0); // padding to make jump table entry 4 bytes wide + } + } + + JumpTable jt = new JumpTable(jumpTablePos, op.lowKey, highKey, 4); + tasm.targetMethod.addAnnotation(jt); + } + + @Override + protected void emitBranch(LIRBranch op) { + + assert assertEmitBranch(op); + + if (op.cond() == Condition.TRUE) { + if (op.info != null) { + int codePos = codePos(); + if (codePos <= tasm.lastSafepointPos()) { + masm.nop(); + } + tasm.recordImplicitException(codePos(), op.info); + } + masm.jmp(op.label()); + } else { + ConditionFlag acond = ConditionFlag.zero; + if (op.code == LIROpcode.CondFloatBranch) { + assert op.unorderedBlock() != null : "must have unordered successor"; + masm.jcc(ConditionFlag.parity, op.unorderedBlock().label()); + // Checkstyle: off + switch (op.cond()) { + case EQ : acond = ConditionFlag.equal; break; + case NE : acond = ConditionFlag.notEqual; break; + case LT : acond = ConditionFlag.below; break; + case LE : acond = ConditionFlag.belowEqual; break; + case GE : acond = ConditionFlag.aboveEqual; break; + case GT : acond = ConditionFlag.above; break; + default : throw Util.shouldNotReachHere(); + } + } else { + switch (op.cond()) { + case EQ : acond = ConditionFlag.equal; break; + case NE : acond = ConditionFlag.notEqual; break; + case LT : acond = ConditionFlag.less; break; + case LE : acond = ConditionFlag.lessEqual; break; + case GE : acond = ConditionFlag.greaterEqual; break; + case GT : acond = ConditionFlag.greater; break; + case BE : acond = ConditionFlag.belowEqual; break; + case AE : acond = ConditionFlag.aboveEqual; break; + default : throw Util.shouldNotReachHere(); + } + // Checkstyle: on + } + masm.jcc(acond, op.label()); + } + } + + @Override + protected void emitConvert(LIRConvert op) { + CiValue src = op.operand(); + CiValue dest = op.result(); + Label endLabel = new Label(); + CiRegister srcRegister = src.asRegister(); + switch (op.bytecode) { + case I2L: + masm.movslq(dest.asRegister(), srcRegister); + break; + + case L2I: + moveRegs(srcRegister, dest.asRegister()); + masm.andl(dest.asRegister(), 0xFFFFFFFF); + break; + + case I2B: + moveRegs(srcRegister, dest.asRegister()); + masm.signExtendByte(dest.asRegister()); + break; + + case I2C: + moveRegs(srcRegister, dest.asRegister()); + masm.andl(dest.asRegister(), 0xFFFF); + break; + + case I2S: + moveRegs(srcRegister, dest.asRegister()); + masm.signExtendShort(dest.asRegister()); + break; + + case F2D: + masm.cvtss2sd(asXmmDoubleReg(dest), asXmmFloatReg(src)); + break; + + case D2F: + masm.cvtsd2ss(asXmmFloatReg(dest), asXmmDoubleReg(src)); + break; + + case I2F: + masm.cvtsi2ssl(asXmmFloatReg(dest), srcRegister); + break; + case I2D: + masm.cvtsi2sdl(asXmmDoubleReg(dest), srcRegister); + break; + + case F2I: { + assert srcRegister.isFpu() && dest.isRegister() : "must both be XMM register (no fpu stack)"; + masm.cvttss2sil(dest.asRegister(), srcRegister); + masm.cmp32(dest.asRegister(), Integer.MIN_VALUE); + masm.jcc(ConditionFlag.notEqual, endLabel); + callGlobalStub(op.globalStub, null, dest.asRegister(), src); + // cannot cause an exception + masm.bind(endLabel); + break; + } + case D2I: { + assert srcRegister.isFpu() && dest.isRegister() : "must both be XMM register (no fpu stack)"; + masm.cvttsd2sil(dest.asRegister(), asXmmDoubleReg(src)); + masm.cmp32(dest.asRegister(), Integer.MIN_VALUE); + masm.jcc(ConditionFlag.notEqual, endLabel); + callGlobalStub(op.globalStub, null, dest.asRegister(), src); + // cannot cause an exception + masm.bind(endLabel); + break; + } + case L2F: + masm.cvtsi2ssq(asXmmFloatReg(dest), srcRegister); + break; + + case L2D: + masm.cvtsi2sdq(asXmmDoubleReg(dest), srcRegister); + break; + + case F2L: { + assert srcRegister.isFpu() && dest.kind.isLong() : "must both be XMM register (no fpu stack)"; + masm.cvttss2siq(dest.asRegister(), asXmmFloatReg(src)); + masm.movq(rscratch1, java.lang.Long.MIN_VALUE); + masm.cmpq(dest.asRegister(), rscratch1); + masm.jcc(ConditionFlag.notEqual, endLabel); + callGlobalStub(op.globalStub, null, dest.asRegister(), src); + masm.bind(endLabel); + break; + } + + case D2L: { + assert srcRegister.isFpu() && dest.kind.isLong() : "must both be XMM register (no fpu stack)"; + masm.cvttsd2siq(dest.asRegister(), asXmmDoubleReg(src)); + masm.movq(rscratch1, java.lang.Long.MIN_VALUE); + masm.cmpq(dest.asRegister(), rscratch1); + masm.jcc(ConditionFlag.notEqual, endLabel); + callGlobalStub(op.globalStub, null, dest.asRegister(), src); + masm.bind(endLabel); + break; + } + + case MOV_I2F: + masm.movdl(asXmmFloatReg(dest), srcRegister); + break; + + case MOV_L2D: + masm.movdq(asXmmDoubleReg(dest), srcRegister); + break; + + case MOV_F2I: + masm.movdl(dest.asRegister(), asXmmFloatReg(src)); + break; + + case MOV_D2L: + masm.movdq(dest.asRegister(), asXmmDoubleReg(src)); + break; + + default: + throw Util.shouldNotReachHere(); + } + } + + @Override + protected void emitCompareAndSwap(LIRCompareAndSwap op) { + CiAddress address = new CiAddress(CiKind.Object, op.address(), 0); + CiRegister newval = op.newValue().asRegister(); + CiRegister cmpval = op.expectedValue().asRegister(); + assert cmpval == AMD64.rax : "wrong register"; + assert newval != null : "new val must be register"; + assert cmpval != newval : "cmp and new values must be in different registers"; + assert cmpval != address.base() : "cmp and addr must be in different registers"; + assert newval != address.base() : "new value and addr must be in different registers"; + assert cmpval != address.index() : "cmp and addr must be in different registers"; + assert newval != address.index() : "new value and addr must be in different registers"; + if (compilation.target.isMP) { + masm.lock(); + } + if (op.code == LIROpcode.CasInt) { + masm.cmpxchgl(newval, address); + } else { + assert op.code == LIROpcode.CasObj || op.code == LIROpcode.CasLong || op.code == LIROpcode.CasWord; + masm.cmpxchgq(newval, address); + } + } + + @Override + protected void emitConditionalMove(Condition condition, CiValue opr1, CiValue opr2, CiValue result) { + ConditionFlag acond; + ConditionFlag ncond; + switch (condition) { + case EQ: + acond = ConditionFlag.equal; + ncond = ConditionFlag.notEqual; + break; + case NE: + acond = ConditionFlag.notEqual; + ncond = ConditionFlag.equal; + break; + case LT: + acond = ConditionFlag.less; + ncond = ConditionFlag.greaterEqual; + break; + case LE: + acond = ConditionFlag.lessEqual; + ncond = ConditionFlag.greater; + break; + case GE: + acond = ConditionFlag.greaterEqual; + ncond = ConditionFlag.less; + break; + case GT: + acond = ConditionFlag.greater; + ncond = ConditionFlag.lessEqual; + break; + case BE: + acond = ConditionFlag.belowEqual; + ncond = ConditionFlag.above; + break; + case BT: + acond = ConditionFlag.below; + ncond = ConditionFlag.aboveEqual; + break; + case AE: + acond = ConditionFlag.aboveEqual; + ncond = ConditionFlag.below; + break; + case AT: + acond = ConditionFlag.above; + ncond = ConditionFlag.belowEqual; + break; + default: + throw Util.shouldNotReachHere(); + } + + CiValue def = opr1; // assume left operand as default + CiValue other = opr2; + + if (opr2.isRegister() && opr2.asRegister() == result.asRegister()) { + // if the right operand is already in the result register, then use it as the default + def = opr2; + other = opr1; + // and flip the condition + ConditionFlag tcond = acond; + acond = ncond; + ncond = tcond; + } + + if (def.isRegister()) { + reg2reg(def, result); + } else if (def.isStackSlot()) { + stack2reg(def, result, result.kind); + } else { + assert def.isConstant(); + const2reg(def, result, null); + } + + if (!other.isConstant()) { + // optimized version that does not require a branch + if (other.isRegister()) { + assert other.asRegister() != result.asRegister() : "other already overwritten by previous move"; + if (other.kind.isInt()) { + masm.cmovq(ncond, result.asRegister(), other.asRegister()); + } else { + masm.cmovq(ncond, result.asRegister(), other.asRegister()); + } + } else { + assert other.isStackSlot(); + CiStackSlot otherSlot = (CiStackSlot) other; + if (other.kind.isInt()) { + masm.cmovl(ncond, result.asRegister(), frameMap.toStackAddress(otherSlot)); + } else { + masm.cmovq(ncond, result.asRegister(), frameMap.toStackAddress(otherSlot)); + } + } + + } else { + // conditional move not available, use emit a branch and move + Label skip = new Label(); + masm.jcc(acond, skip); + if (other.isRegister()) { + reg2reg(other, result); + } else if (other.isStackSlot()) { + stack2reg(other, result, result.kind); + } else { + assert other.isConstant(); + const2reg(other, result, null); + } + masm.bind(skip); + } + } + + @Override + protected void emitArithOp(LIROpcode code, CiValue left, CiValue right, CiValue dest, LIRDebugInfo info) { + assert info == null : "should never be used : idiv/irem and ldiv/lrem not handled by this method"; + assert Util.archKindsEqual(left.kind, right.kind) || (left.kind == CiKind.Word && right.kind == CiKind.Int) : code.toString() + " left arch is " + left.kind + " and right arch is " + right.kind; + assert left.equals(dest) : "left and dest must be equal"; + CiKind kind = left.kind; + + // Checkstyle: off + if (left.isRegister()) { + CiRegister lreg = left.asRegister(); + + if (right.isRegister()) { + // register - register + CiRegister rreg = right.asRegister(); + if (kind.isInt()) { + switch (code) { + case Add : masm.addl(lreg, rreg); break; + case Sub : masm.subl(lreg, rreg); break; + case Mul : masm.imull(lreg, rreg); break; + default : throw Util.shouldNotReachHere(); + } + } else if (kind.isFloat()) { + assert rreg.isFpu() : "must be xmm"; + switch (code) { + case Add : masm.addss(lreg, rreg); break; + case Sub : masm.subss(lreg, rreg); break; + case Mul : masm.mulss(lreg, rreg); break; + case Div : masm.divss(lreg, rreg); break; + default : throw Util.shouldNotReachHere(); + } + } else if (kind.isDouble()) { + assert rreg.isFpu(); + switch (code) { + case Add : masm.addsd(lreg, rreg); break; + case Sub : masm.subsd(lreg, rreg); break; + case Mul : masm.mulsd(lreg, rreg); break; + case Div : masm.divsd(lreg, rreg); break; + default : throw Util.shouldNotReachHere(); + } + } else { + assert target.sizeInBytes(kind) == 8; + switch (code) { + case Add : masm.addq(lreg, rreg); break; + case Sub : masm.subq(lreg, rreg); break; + case Mul : masm.imulq(lreg, rreg); break; + default : throw Util.shouldNotReachHere(); + } + } + } else { + if (kind.isInt()) { + if (right.isStackSlot()) { + // register - stack + CiAddress raddr = frameMap.toStackAddress(((CiStackSlot) right)); + switch (code) { + case Add : masm.addl(lreg, raddr); break; + case Sub : masm.subl(lreg, raddr); break; + default : throw Util.shouldNotReachHere(); + } + } else if (right.isConstant()) { + // register - constant + assert kind.isInt(); + int delta = ((CiConstant) right).asInt(); + switch (code) { + case Add : masm.incrementl(lreg, delta); break; + case Sub : masm.decrementl(lreg, delta); break; + default : throw Util.shouldNotReachHere(); + } + } + } else if (kind.isFloat()) { + // register - stack/constant + CiAddress raddr; + if (right.isStackSlot()) { + raddr = frameMap.toStackAddress(((CiStackSlot) right)); + } else { + assert right.isConstant(); + raddr = tasm.recordDataReferenceInCode(CiConstant.forFloat(((CiConstant) right).asFloat())); + } + switch (code) { + case Add : masm.addss(lreg, raddr); break; + case Sub : masm.subss(lreg, raddr); break; + case Mul : masm.mulss(lreg, raddr); break; + case Div : masm.divss(lreg, raddr); break; + default : throw Util.shouldNotReachHere(); + } + } else if (kind.isDouble()) { + // register - stack/constant + CiAddress raddr; + if (right.isStackSlot()) { + raddr = frameMap.toStackAddress(((CiStackSlot) right)); + } else { + assert right.isConstant(); + raddr = tasm.recordDataReferenceInCode(CiConstant.forDouble(((CiConstant) right).asDouble())); + } + switch (code) { + case Add : masm.addsd(lreg, raddr); break; + case Sub : masm.subsd(lreg, raddr); break; + case Mul : masm.mulsd(lreg, raddr); break; + case Div : masm.divsd(lreg, raddr); break; + default : throw Util.shouldNotReachHere(); + } + } else { + assert target.sizeInBytes(kind) == 8; + if (right.isStackSlot()) { + // register - stack + CiAddress raddr = frameMap.toStackAddress(((CiStackSlot) right)); + switch (code) { + case Add : masm.addq(lreg, raddr); break; + case Sub : masm.subq(lreg, raddr); break; + default : throw Util.shouldNotReachHere(); + } + } else { + // register - constant + assert right.isConstant(); + long c = ((CiConstant) right).asLong(); + if (NumUtil.isInt(c)) { + switch (code) { + case Add : masm.addq(lreg, (int) c); break; + case Sub : masm.subq(lreg, (int) c); break; + default : throw Util.shouldNotReachHere(); + } + } else { + masm.movq(rscratch1, c); + switch (code) { + case Add : masm.addq(lreg, rscratch1); break; + case Sub : masm.subq(lreg, rscratch1); break; + default : throw Util.shouldNotReachHere(); + } + } + } + } + } + } else { + assert kind.isInt(); + CiAddress laddr = asAddress(left); + + if (right.isRegister()) { + CiRegister rreg = right.asRegister(); + switch (code) { + case Add : masm.addl(laddr, rreg); break; + case Sub : masm.subl(laddr, rreg); break; + default : throw Util.shouldNotReachHere(); + } + } else { + assert right.isConstant(); + int c = ((CiConstant) right).asInt(); + switch (code) { + case Add : masm.incrementl(laddr, c); break; + case Sub : masm.decrementl(laddr, c); break; + default : throw Util.shouldNotReachHere(); + } + } + } + // Checkstyle: on + } + + @Override + protected void emitIntrinsicOp(LIROpcode code, CiValue value, CiValue unused, CiValue dest, LIROp2 op) { + assert value.kind.isDouble(); + switch (code) { + case Abs: + if (asXmmDoubleReg(dest) != asXmmDoubleReg(value)) { + masm.movdbl(asXmmDoubleReg(dest), asXmmDoubleReg(value)); + } + masm.andpd(asXmmDoubleReg(dest), tasm.recordDataReferenceInCode(CiConstant.forLong(DoubleSignMask))); + break; + + case Sqrt: + masm.sqrtsd(asXmmDoubleReg(dest), asXmmDoubleReg(value)); + break; + + default: + throw Util.shouldNotReachHere(); + } + } + + @Override + protected void emitLogicOp(LIROpcode code, CiValue left, CiValue right, CiValue dst) { + assert left.isRegister(); + // Checkstyle: off + if (left.kind.isInt()) { + CiRegister reg = left.asRegister(); + if (right.isConstant()) { + int val = ((CiConstant) right).asInt(); + switch (code) { + case LogicAnd : masm.andl(reg, val); break; + case LogicOr : masm.orl(reg, val); break; + case LogicXor : masm.xorl(reg, val); break; + default : throw Util.shouldNotReachHere(); + } + } else if (right.isStackSlot()) { + // added support for stack operands + CiAddress raddr = frameMap.toStackAddress(((CiStackSlot) right)); + switch (code) { + case LogicAnd : masm.andl(reg, raddr); break; + case LogicOr : masm.orl(reg, raddr); break; + case LogicXor : masm.xorl(reg, raddr); break; + default : throw Util.shouldNotReachHere(); + } + } else { + CiRegister rright = right.asRegister(); + switch (code) { + case LogicAnd : masm.andq(reg, rright); break; + case LogicOr : masm.orq(reg, rright); break; + case LogicXor : masm.xorptr(reg, rright); break; + default : throw Util.shouldNotReachHere(); + } + } + moveRegs(reg, dst.asRegister()); + } else { + assert target.sizeInBytes(left.kind) == 8; + CiRegister lreg = left.asRegister(); + if (right.isConstant()) { + CiConstant rightConstant = (CiConstant) right; + masm.movq(rscratch1, rightConstant.asLong()); + switch (code) { + case LogicAnd : masm.andq(lreg, rscratch1); break; + case LogicOr : masm.orq(lreg, rscratch1); break; + case LogicXor : masm.xorq(lreg, rscratch1); break; + default : throw Util.shouldNotReachHere(); + } + } else { + CiRegister rreg = right.asRegister(); + switch (code) { + case LogicAnd : masm.andq(lreg, rreg); break; + case LogicOr : masm.orq(lreg, rreg); break; + case LogicXor : masm.xorptr(lreg, rreg); break; + default : throw Util.shouldNotReachHere(); + } + } + + CiRegister dreg = dst.asRegister(); + moveRegs(lreg, dreg); + } + // Checkstyle: on + } + + void arithmeticIdiv(LIROpcode code, CiValue left, CiValue right, CiValue result, LIRDebugInfo info) { + assert left.isRegister() : "left must be register"; + assert right.isRegister() || right.isConstant() : "right must be register or constant"; + assert result.isRegister() : "result must be register"; + + CiRegister lreg = left.asRegister(); + CiRegister dreg = result.asRegister(); + + if (right.isConstant()) { + int divisor = ((CiConstant) right).asInt(); + assert divisor > 0 && CiUtil.isPowerOf2(divisor) : "divisor must be power of two"; + if (code == LIROpcode.Idiv) { + assert lreg == AMD64.rax : "dividend must be rax"; + masm.cdql(); // sign extend into rdx:rax + if (divisor == 2) { + masm.subl(lreg, AMD64.rdx); + } else { + masm.andl(AMD64.rdx, divisor - 1); + masm.addl(lreg, AMD64.rdx); + } + masm.sarl(lreg, CiUtil.log2(divisor)); + moveRegs(lreg, dreg); + } else { + assert code == LIROpcode.Irem; + Label done = new Label(); + masm.mov(dreg, lreg); + masm.andl(dreg, 0x80000000 | (divisor - 1)); + masm.jcc(ConditionFlag.positive, done); + masm.decrementl(dreg, 1); + masm.orl(dreg, ~(divisor - 1)); + masm.incrementl(dreg, 1); + masm.bind(done); + } + } else { + CiRegister rreg = right.asRegister(); + assert lreg == AMD64.rax : "left register must be rax"; + assert rreg != AMD64.rdx : "right register must not be rdx"; + + moveRegs(lreg, AMD64.rax); + + Label continuation = new Label(); + + if (C1XOptions.GenSpecialDivChecks) { + // check for special case of Integer.MIN_VALUE / -1 + Label normalCase = new Label(); + masm.cmpl(AMD64.rax, Integer.MIN_VALUE); + masm.jcc(ConditionFlag.notEqual, normalCase); + if (code == LIROpcode.Irem) { + // prepare X86Register.rdx for possible special case where remainder = 0 + masm.xorl(AMD64.rdx, AMD64.rdx); + } + masm.cmpl(rreg, -1); + masm.jcc(ConditionFlag.equal, continuation); + + // handle normal case + masm.bind(normalCase); + } + masm.cdql(); + int offset = masm.codeBuffer.position(); + masm.idivl(rreg); + + // normal and special case exit + masm.bind(continuation); + + tasm.recordImplicitException(offset, info); + if (code == LIROpcode.Irem) { + moveRegs(AMD64.rdx, dreg); // result is in rdx + } else { + assert code == LIROpcode.Idiv; + moveRegs(AMD64.rax, dreg); + } + } + } + + void arithmeticLdiv(LIROpcode code, CiValue left, CiValue right, CiValue result, LIRDebugInfo info) { + assert left.isRegister() : "left must be register"; + assert right.isRegister() : "right must be register"; + assert result.isRegister() : "result must be register"; + assert result.kind.isLong(); + + CiRegister lreg = left.asRegister(); + CiRegister dreg = result.asRegister(); + CiRegister rreg = right.asRegister(); + assert lreg == AMD64.rax : "left register must be rax"; + assert rreg != AMD64.rdx : "right register must not be rdx"; + + moveRegs(lreg, AMD64.rax); + + Label continuation = new Label(); + + if (C1XOptions.GenSpecialDivChecks) { + // check for special case of Long.MIN_VALUE / -1 + Label normalCase = new Label(); + masm.movq(AMD64.rdx, java.lang.Long.MIN_VALUE); + masm.cmpq(AMD64.rax, AMD64.rdx); + masm.jcc(ConditionFlag.notEqual, normalCase); + if (code == LIROpcode.Lrem) { + // prepare X86Register.rdx for possible special case (where remainder = 0) + masm.xorq(AMD64.rdx, AMD64.rdx); + } + masm.cmpl(rreg, -1); + masm.jcc(ConditionFlag.equal, continuation); + + // handle normal case + masm.bind(normalCase); + } + masm.cdqq(); + int offset = masm.codeBuffer.position(); + masm.idivq(rreg); + + // normal and special case exit + masm.bind(continuation); + + tasm.recordImplicitException(offset, info); + if (code == LIROpcode.Lrem) { + moveRegs(AMD64.rdx, dreg); + } else { + assert code == LIROpcode.Ldiv; + moveRegs(AMD64.rax, dreg); + } + } + + void arithmeticWdiv(LIROpcode code, CiValue left, CiValue right, CiValue result, LIRDebugInfo info) { + assert left.isRegister() : "left must be register"; + assert right.isRegister() : "right must be register"; + assert result.isRegister() : "result must be register"; + + CiRegister lreg = left.asRegister(); + CiRegister dreg = result.asRegister(); + CiRegister rreg = right.asRegister(); + assert lreg == AMD64.rax : "left register must be rax"; + assert rreg != AMD64.rdx : "right register must not be rdx"; + + // Must zero the high 64-bit word (in RDX) of the dividend + masm.xorq(AMD64.rdx, AMD64.rdx); + + if (code == LIROpcode.Wdivi || code == LIROpcode.Wremi) { + // Zero the high 32 bits of the divisor + masm.movzxd(rreg, rreg); + } + + moveRegs(lreg, AMD64.rax); + + int offset = masm.codeBuffer.position(); + masm.divq(rreg); + + tasm.recordImplicitException(offset, info); + if (code == LIROpcode.Wrem || code == LIROpcode.Wremi) { + moveRegs(AMD64.rdx, dreg); + } else { + assert code == LIROpcode.Wdiv || code == LIROpcode.Wdivi; + moveRegs(AMD64.rax, dreg); + } + } + + @Override + protected void emitCompare(Condition condition, CiValue opr1, CiValue opr2, LIROp2 op) { + // Checkstyle: off + assert Util.archKindsEqual(opr1.kind.stackKind(), opr2.kind.stackKind()) || (opr1.kind == CiKind.Word && opr2.kind == CiKind.Int) : "nonmatching stack kinds (" + condition + "): " + opr1.kind.stackKind() + "==" + opr2.kind.stackKind(); + + if (opr1.isConstant()) { + // Use scratch register + CiValue newOpr1 = compilation.registerConfig.getScratchRegister().asValue(opr1.kind); + const2reg(opr1, newOpr1, null); + opr1 = newOpr1; + } + + if (opr1.isRegister()) { + CiRegister reg1 = opr1.asRegister(); + if (opr2.isRegister()) { + // register - register + switch (opr1.kind) { + case Boolean : + case Byte : + case Char : + case Short : + case Int : masm.cmpl(reg1, opr2.asRegister()); break; + case Long : + case Word : + case Object : masm.cmpq(reg1, opr2.asRegister()); break; + case Float : masm.ucomiss(reg1, asXmmFloatReg(opr2)); break; + case Double : masm.ucomisd(reg1, asXmmDoubleReg(opr2)); break; + default : throw Util.shouldNotReachHere(opr1.kind.toString()); + } + } else if (opr2.isStackSlot()) { + // register - stack + CiStackSlot opr2Slot = (CiStackSlot) opr2; + switch (opr1.kind) { + case Boolean : + case Byte : + case Char : + case Short : + case Int : masm.cmpl(reg1, frameMap.toStackAddress(opr2Slot)); break; + case Long : + case Word : + case Object : masm.cmpptr(reg1, frameMap.toStackAddress(opr2Slot)); break; + case Float : masm.ucomiss(reg1, frameMap.toStackAddress(opr2Slot)); break; + case Double : masm.ucomisd(reg1, frameMap.toStackAddress(opr2Slot)); break; + default : throw Util.shouldNotReachHere(); + } + } else if (opr2.isConstant()) { + // register - constant + CiConstant c = (CiConstant) opr2; + switch (opr1.kind) { + case Boolean : + case Byte : + case Char : + case Short : + case Int : masm.cmpl(reg1, c.asInt()); break; + case Float : masm.ucomiss(reg1, tasm.recordDataReferenceInCode(CiConstant.forFloat(((CiConstant) opr2).asFloat()))); break; + case Double : masm.ucomisd(reg1, tasm.recordDataReferenceInCode(CiConstant.forDouble(((CiConstant) opr2).asDouble()))); break; + case Long : + case Word : { + if (c.asLong() == 0) { + masm.cmpq(reg1, 0); + } else { + masm.movq(rscratch1, c.asLong()); + masm.cmpq(reg1, rscratch1); + + } + break; + } + case Object : { + movoop(rscratch1, c); + masm.cmpq(reg1, rscratch1); + break; + } + default : throw Util.shouldNotReachHere(); + } + } else { + throw Util.shouldNotReachHere(); + } + } else if (opr1.isStackSlot()) { + CiAddress left = asAddress(opr1); + if (opr2.isConstant()) { + CiConstant right = (CiConstant) opr2; + // stack - constant + switch (opr1.kind) { + case Boolean : + case Byte : + case Char : + case Short : + case Int : masm.cmpl(left, right.asInt()); break; + case Long : + case Word : assert NumUtil.isInt(right.asLong()); + masm.cmpq(left, right.asInt()); break; + case Object : assert right.isNull(); + masm.cmpq(left, 0); break; + default : throw Util.shouldNotReachHere(); + } + } else { + throw Util.shouldNotReachHere(); + } + + } else { + throw Util.shouldNotReachHere(opr1.toString() + " opr2 = " + opr2); + } + // Checkstyle: on + } + + @Override + protected void emitCompare2Int(LIROpcode code, CiValue left, CiValue right, CiValue dst, LIROp2 op) { + if (code == LIROpcode.Cmpfd2i || code == LIROpcode.Ucmpfd2i) { + if (left.kind.isFloat()) { + masm.cmpss2int(asXmmFloatReg(left), asXmmFloatReg(right), dst.asRegister(), code == LIROpcode.Ucmpfd2i); + } else if (left.kind.isDouble()) { + masm.cmpsd2int(asXmmDoubleReg(left), asXmmDoubleReg(right), dst.asRegister(), code == LIROpcode.Ucmpfd2i); + } else { + assert false : "no fpu stack"; + } + } else { + assert code == LIROpcode.Cmpl2i; + CiRegister dest = dst.asRegister(); + Label high = new Label(); + Label done = new Label(); + Label isEqual = new Label(); + masm.cmpptr(left.asRegister(), right.asRegister()); + masm.jcc(ConditionFlag.equal, isEqual); + masm.jcc(ConditionFlag.greater, high); + masm.xorptr(dest, dest); + masm.decrementl(dest, 1); + masm.jmp(done); + masm.bind(high); + masm.xorptr(dest, dest); + masm.incrementl(dest, 1); + masm.jmp(done); + masm.bind(isEqual); + masm.xorptr(dest, dest); + masm.bind(done); + } + } + + @Override + protected void emitCallAlignment(LIROpcode code) { + if (C1XOptions.AlignCallsForPatching) { + // make sure that the displacement word of the call ends up word aligned + int offset = masm.codeBuffer.position(); + offset += compilation.target.arch.machineCodeCallDisplacementOffset; + while (offset++ % wordSize != 0) { + masm.nop(); + } + } + } + + @Override + protected void emitIndirectCall(Object target, LIRDebugInfo info, CiValue callAddress) { + CiRegister reg = rscratch1; + if (callAddress.isRegister()) { + reg = callAddress.asRegister(); + } else { + moveOp(callAddress, reg.asValue(callAddress.kind), callAddress.kind, null, false); + } + indirectCall(reg, target, info); + } + + @Override + protected void emitDirectCall(Object target, LIRDebugInfo info) { + directCall(target, info); + } + + @Override + protected void emitNativeCall(String symbol, LIRDebugInfo info, CiValue callAddress) { + CiRegister reg = rscratch1; + if (callAddress.isRegister()) { + reg = callAddress.asRegister(); + } else { + moveOp(callAddress, reg.asValue(callAddress.kind), callAddress.kind, null, false); + } + indirectCall(reg, symbol, info); + } + + @Override + protected void emitTemplateCall(CiValue address) { + if (address == null) { + directCall(null, null); + return; + } + + CiRegister reg = rscratch1; + if (address.isRegister()) { + reg = address.asRegister(); + } else { + moveOp(address, reg.asValue(address.kind), address.kind, null, false); + } + indirectCall(reg, null, null); + } + + private void emitXIRShiftOp(LIROpcode code, CiValue left, CiValue count, CiValue dest) { + if (count.isConstant()) { + emitShiftOp(code, left, ((CiConstant) count).asInt(), dest); + } else { + emitShiftOp(code, left, count, dest, IllegalValue); + } + } + + @Override + protected void emitShiftOp(LIROpcode code, CiValue left, CiValue count, CiValue dest, CiValue tmp) { + // optimized version for linear scan: + // * count must be already in ECX (guaranteed by LinearScan) + // * left and dest must be equal + // * tmp must be unused + assert count.asRegister() == SHIFTCount : "count must be in ECX"; + assert left == dest : "left and dest must be equal"; + assert tmp.isIllegal() : "wasting a register if tmp is allocated"; + assert left.isRegister(); + + if (left.kind.isInt()) { + CiRegister value = left.asRegister(); + assert value != SHIFTCount : "left cannot be ECX"; + + // Checkstyle: off + switch (code) { + case Shl : masm.shll(value); break; + case Shr : masm.sarl(value); break; + case Ushr : masm.shrl(value); break; + default : throw Util.shouldNotReachHere(); + } + } else { + CiRegister lreg = left.asRegister(); + assert lreg != SHIFTCount : "left cannot be ECX"; + + switch (code) { + case Shl : masm.shlq(lreg); break; + case Shr : masm.sarq(lreg); break; + case Ushr : masm.shrq(lreg); break; + default : throw Util.shouldNotReachHere(); + } + // Checkstyle: on + } + } + + @Override + protected void emitShiftOp(LIROpcode code, CiValue left, int count, CiValue dest) { + assert dest.isRegister(); + if (dest.kind.isInt()) { + // first move left into dest so that left is not destroyed by the shift + CiRegister value = dest.asRegister(); + count = count & 0x1F; // Java spec + + moveRegs(left.asRegister(), value); + // Checkstyle: off + switch (code) { + case Shl : masm.shll(value, count); break; + case Shr : masm.sarl(value, count); break; + case Ushr : masm.shrl(value, count); break; + default : throw Util.shouldNotReachHere(); + } + } else { + + // first move left into dest so that left is not destroyed by the shift + CiRegister value = dest.asRegister(); + count = count & 0x1F; // Java spec + + moveRegs(left.asRegister(), value); + switch (code) { + case Shl : masm.shlq(value, count); break; + case Shr : masm.sarq(value, count); break; + case Ushr : masm.shrq(value, count); break; + default : throw Util.shouldNotReachHere(); + } + // Checkstyle: on + } + } + + @Override + protected void emitSignificantBitOp(boolean most, CiValue src, CiValue dst) { + assert dst.isRegister(); + CiRegister result = dst.asRegister(); + masm.xorq(result, result); + masm.notq(result); + if (src.isRegister()) { + CiRegister value = src.asRegister(); + assert value != result; + if (most) { + masm.bsrq(result, value); + } else { + masm.bsfq(result, value); + } + } else { + CiAddress laddr = asAddress(src); + if (most) { + masm.bsrq(result, laddr); + } else { + masm.bsfq(result, laddr); + } + } + } + + @Override + protected void emitAlignment() { + masm.align(wordSize); + } + + @Override + protected void emitNegate(LIRNegate op) { + CiValue left = op.operand(); + CiValue dest = op.result(); + assert left.isRegister(); + if (left.kind.isInt()) { + masm.negl(left.asRegister()); + moveRegs(left.asRegister(), dest.asRegister()); + + } else if (dest.kind.isFloat()) { + if (asXmmFloatReg(left) != asXmmFloatReg(dest)) { + masm.movflt(asXmmFloatReg(dest), asXmmFloatReg(left)); + } + callGlobalStub(op.globalStub, null, asXmmFloatReg(dest), dest); + + } else if (dest.kind.isDouble()) { + if (asXmmDoubleReg(left) != asXmmDoubleReg(dest)) { + masm.movdbl(asXmmDoubleReg(dest), asXmmDoubleReg(left)); + } + + callGlobalStub(op.globalStub, null, asXmmDoubleReg(dest), dest); + } else { + CiRegister lreg = left.asRegister(); + CiRegister dreg = dest.asRegister(); + masm.movq(dreg, lreg); + masm.negq(dreg); + } + } + + @Override + protected void emitLea(CiValue src, CiValue dest) { + CiRegister reg = dest.asRegister(); + masm.leaq(reg, asAddress(src)); + } + + @Override + protected void emitNullCheck(CiValue src, LIRDebugInfo info) { + assert src.isRegister(); + if (C1XOptions.NullCheckUniquePc) { + masm.nop(); + } + tasm.recordImplicitException(codePos(), info); + masm.nullCheck(src.asRegister()); + } + + @Override + protected void emitVolatileMove(CiValue src, CiValue dest, CiKind kind, LIRDebugInfo info) { + assert kind == CiKind.Long : "only for volatile long fields"; + + if (info != null) { + tasm.recordImplicitException(codePos(), info); + } + + if (src.kind.isDouble()) { + if (dest.isRegister()) { + masm.movdq(dest.asRegister(), asXmmDoubleReg(src)); + } else if (dest.isStackSlot()) { + masm.movsd(frameMap.toStackAddress((CiStackSlot) dest), asXmmDoubleReg(src)); + } else { + assert dest.isAddress(); + masm.movsd((CiAddress) dest, asXmmDoubleReg(src)); + } + } else { + assert dest.kind.isDouble(); + if (src.isStackSlot()) { + masm.movdbl(asXmmDoubleReg(dest), frameMap.toStackAddress((CiStackSlot) src)); + } else { + assert src.isAddress(); + masm.movdbl(asXmmDoubleReg(dest), (CiAddress) src); + } + } + } + + private static CiRegister asXmmDoubleReg(CiValue dest) { + assert dest.kind.isDouble() : "must be double XMM register"; + CiRegister result = dest.asRegister(); + assert result.isFpu() : "must be XMM register"; + return result; + } + + @Override + protected void emitMemoryBarriers(int barriers) { + masm.membar(barriers); + } + + @Override + protected void doPeephole(LIRList list) { + // Do nothing for now + } + + @Override + protected void emitXir(LIRXirInstruction instruction) { + XirSnippet snippet = instruction.snippet; + + Label[] labels = new Label[snippet.template.labels.length]; + for (int i = 0; i < labels.length; i++) { + labels[i] = new Label(); + } + emitXirInstructions(instruction, snippet.template.fastPath, labels, instruction.getOperands(), snippet.marks); + if (snippet.template.slowPath != null) { + addSlowPath(new SlowPath(instruction, labels, snippet.marks)); + } + } + + @Override + protected void emitSlowPath(SlowPath sp) { + int start = -1; + if (C1XOptions.TraceAssembler) { + TTY.println("Emitting slow path for XIR instruction " + sp.instruction.snippet.template.name); + start = masm.codeBuffer.position(); + } + emitXirInstructions(sp.instruction, sp.instruction.snippet.template.slowPath, sp.labels, sp.instruction.getOperands(), sp.marks); + masm.nop(); + if (C1XOptions.TraceAssembler) { + TTY.println("From " + start + " to " + masm.codeBuffer.position()); + } + } + + public void emitXirInstructions(LIRXirInstruction xir, XirInstruction[] instructions, Label[] labels, CiValue[] operands, Map marks) { + LIRDebugInfo info = xir == null ? null : xir.info; + LIRDebugInfo infoAfter = xir == null ? null : xir.infoAfter; + + for (XirInstruction inst : instructions) { + switch (inst.op) { + case Add: + emitArithOp(LIROpcode.Add, operands[inst.x().index], operands[inst.y().index], operands[inst.result.index], null); + break; + + case Sub: + emitArithOp(LIROpcode.Sub, operands[inst.x().index], operands[inst.y().index], operands[inst.result.index], null); + break; + + case Div: + if (inst.kind == CiKind.Int) { + arithmeticIdiv(LIROpcode.Idiv, operands[inst.x().index], operands[inst.y().index], operands[inst.result.index], null); + } else { + emitArithOp(LIROpcode.Div, operands[inst.x().index], operands[inst.y().index], operands[inst.result.index], null); + } + break; + + case Mul: + emitArithOp(LIROpcode.Mul, operands[inst.x().index], operands[inst.y().index], operands[inst.result.index], null); + break; + + case Mod: + if (inst.kind == CiKind.Int) { + arithmeticIdiv(LIROpcode.Irem, operands[inst.x().index], operands[inst.y().index], operands[inst.result.index], null); + } else { + emitArithOp(LIROpcode.Rem, operands[inst.x().index], operands[inst.y().index], operands[inst.result.index], null); + } + break; + + case Shl: + emitXIRShiftOp(LIROpcode.Shl, operands[inst.x().index], operands[inst.y().index], operands[inst.result.index]); + break; + + case Sar: + emitXIRShiftOp(LIROpcode.Shr, operands[inst.x().index], operands[inst.y().index], operands[inst.result.index]); + break; + + case Shr: + emitXIRShiftOp(LIROpcode.Ushr, operands[inst.x().index], operands[inst.y().index], operands[inst.result.index]); + break; + + case And: + emitLogicOp(LIROpcode.LogicAnd, operands[inst.x().index], operands[inst.y().index], operands[inst.result.index]); + break; + + case Or: + emitLogicOp(LIROpcode.LogicOr, operands[inst.x().index], operands[inst.y().index], operands[inst.result.index]); + break; + + case Xor: + emitLogicOp(LIROpcode.LogicXor, operands[inst.x().index], operands[inst.y().index], operands[inst.result.index]); + break; + + case Mov: { + CiValue result = operands[inst.result.index]; + CiValue source = operands[inst.x().index]; + moveOp(source, result, result.kind, null, false); + break; + } + + case PointerLoad: { + if ((Boolean) inst.extra && info != null) { + tasm.recordImplicitException(codePos(), info); + } + + CiValue result = operands[inst.result.index]; + CiValue pointer = operands[inst.x().index]; + CiRegisterValue register = assureInRegister(pointer); + moveOp(new CiAddress(inst.kind, register, 0), result, inst.kind, null, false); + break; + } + + case PointerStore: { + if ((Boolean) inst.extra && info != null) { + tasm.recordImplicitException(codePos(), info); + } + + CiValue value = operands[inst.y().index]; + CiValue pointer = operands[inst.x().index]; + assert pointer.isVariableOrRegister(); + moveOp(value, new CiAddress(inst.kind, pointer, 0), inst.kind, null, false); + break; + } + + case PointerLoadDisp: { + CiXirAssembler.AddressAccessInformation addressInformation = (CiXirAssembler.AddressAccessInformation) inst.extra; + boolean canTrap = addressInformation.canTrap; + + CiAddress.Scale scale = addressInformation.scale; + int displacement = addressInformation.disp; + + CiValue result = operands[inst.result.index]; + CiValue pointer = operands[inst.x().index]; + CiValue index = operands[inst.y().index]; + + pointer = assureInRegister(pointer); + assert pointer.isVariableOrRegister(); + + CiValue src = null; + if (index.isConstant()) { + assert index.kind == CiKind.Int; + CiConstant constantIndex = (CiConstant) index; + src = new CiAddress(inst.kind, pointer, constantIndex.asInt() * scale.value + displacement); + } else { + src = new CiAddress(inst.kind, pointer, index, scale, displacement); + } + + moveOp(src, result, inst.kind, canTrap ? info : null, false); + break; + } + + case LoadEffectiveAddress: { + CiXirAssembler.AddressAccessInformation addressInformation = (CiXirAssembler.AddressAccessInformation) inst.extra; + + CiAddress.Scale scale = addressInformation.scale; + int displacement = addressInformation.disp; + + CiValue result = operands[inst.result.index]; + CiValue pointer = operands[inst.x().index]; + CiValue index = operands[inst.y().index]; + + pointer = assureInRegister(pointer); + assert pointer.isVariableOrRegister(); + CiValue src = new CiAddress(CiKind.Illegal, pointer, index, scale, displacement); + emitLea(src, result); + break; + } + + case PointerStoreDisp: { + CiXirAssembler.AddressAccessInformation addressInformation = (CiXirAssembler.AddressAccessInformation) inst.extra; + boolean canTrap = addressInformation.canTrap; + + CiAddress.Scale scale = addressInformation.scale; + int displacement = addressInformation.disp; + + CiValue value = operands[inst.z().index]; + CiValue pointer = operands[inst.x().index]; + CiValue index = operands[inst.y().index]; + + pointer = assureInRegister(pointer); + assert pointer.isVariableOrRegister(); + + CiValue dst; + if (index.isConstant()) { + assert index.kind == CiKind.Int; + CiConstant constantIndex = (CiConstant) index; + dst = new CiAddress(inst.kind, pointer, IllegalValue, scale, constantIndex.asInt() * scale.value + displacement); + } else { + dst = new CiAddress(inst.kind, pointer, index, scale, displacement); + } + + moveOp(value, dst, inst.kind, canTrap ? info : null, false); + break; + } + + case RepeatMoveBytes: + assert operands[inst.x().index].asRegister().equals(AMD64.rsi) : "wrong input x: " + operands[inst.x().index]; + assert operands[inst.y().index].asRegister().equals(AMD64.rdi) : "wrong input y: " + operands[inst.y().index]; + assert operands[inst.z().index].asRegister().equals(AMD64.rcx) : "wrong input z: " + operands[inst.z().index]; + masm.repeatMoveBytes(); + break; + + case RepeatMoveWords: + assert operands[inst.x().index].asRegister().equals(AMD64.rsi) : "wrong input x: " + operands[inst.x().index]; + assert operands[inst.y().index].asRegister().equals(AMD64.rdi) : "wrong input y: " + operands[inst.y().index]; + assert operands[inst.z().index].asRegister().equals(AMD64.rcx) : "wrong input z: " + operands[inst.z().index]; + masm.repeatMoveWords(); + break; + + case PointerCAS: + + if ((Boolean) inst.extra && info != null) { + tasm.recordImplicitException(codePos(), info); + } + assert operands[inst.x().index].asRegister().equals(AMD64.rax) : "wrong input x: " + operands[inst.x().index]; + + CiValue exchangedVal = operands[inst.y().index]; + CiValue exchangedAddress = operands[inst.x().index]; + CiRegisterValue pointerRegister = assureInRegister(exchangedAddress); + CiAddress addr = new CiAddress(CiKind.Word, pointerRegister); + masm.cmpxchgq(exchangedVal.asRegister(), addr); + + break; + + case CallStub: { + XirTemplate stubId = (XirTemplate) inst.extra; + CiRegister result = CiRegister.None; + if (inst.result != null) { + result = operands[inst.result.index].asRegister(); + } + CiValue[] args = new CiValue[inst.arguments.length]; + for (int i = 0; i < args.length; i++) { + args[i] = operands[inst.arguments[i].index]; + } + callGlobalStub(stubId, info, result, args); + break; + } + case CallRuntime: { + CiKind[] signature = new CiKind[inst.arguments.length]; + for (int i = 0; i < signature.length; i++) { + signature[i] = inst.arguments[i].kind; + } + + CiCallingConvention cc = frameMap.getCallingConvention(signature, RuntimeCall); + for (int i = 0; i < inst.arguments.length; i++) { + CiValue argumentLocation = cc.locations[i]; + CiValue argumentSourceLocation = operands[inst.arguments[i].index]; + if (argumentLocation != argumentSourceLocation) { + moveOp(argumentSourceLocation, argumentLocation, argumentLocation.kind, null, false); + } + } + + RuntimeCallInformation runtimeCallInformation = (RuntimeCallInformation) inst.extra; + directCall(runtimeCallInformation.target, (runtimeCallInformation.useInfoAfter) ? infoAfter : info); + + if (inst.result != null && inst.result.kind != CiKind.Illegal && inst.result.kind != CiKind.Void) { + CiRegister returnRegister = compilation.registerConfig.getReturnRegister(inst.result.kind); + CiValue resultLocation = returnRegister.asValue(inst.result.kind.stackKind()); + moveOp(resultLocation, operands[inst.result.index], inst.result.kind.stackKind(), null, false); + } + break; + } + case Jmp: { + if (inst.extra instanceof XirLabel) { + Label label = labels[((XirLabel) inst.extra).index]; + masm.jmp(label); + } else { + directJmp(inst.extra); + } + break; + } + case DecAndJumpNotZero: { + Label label = labels[((XirLabel) inst.extra).index]; + CiValue value = operands[inst.x().index]; + if (value.kind == CiKind.Long) { + masm.decq(value.asRegister()); + } else { + assert value.kind == CiKind.Int; + masm.decl(value.asRegister()); + } + masm.jcc(ConditionFlag.notZero, label); + break; + } + case Jeq: { + Label label = labels[((XirLabel) inst.extra).index]; + emitXirCompare(inst, Condition.EQ, ConditionFlag.equal, operands, label); + break; + } + case Jneq: { + Label label = labels[((XirLabel) inst.extra).index]; + emitXirCompare(inst, Condition.NE, ConditionFlag.notEqual, operands, label); + break; + } + + case Jgt: { + Label label = labels[((XirLabel) inst.extra).index]; + emitXirCompare(inst, Condition.GT, ConditionFlag.greater, operands, label); + break; + } + + case Jgteq: { + Label label = labels[((XirLabel) inst.extra).index]; + emitXirCompare(inst, Condition.GE, ConditionFlag.greaterEqual, operands, label); + break; + } + + case Jugteq: { + Label label = labels[((XirLabel) inst.extra).index]; + emitXirCompare(inst, Condition.AE, ConditionFlag.aboveEqual, operands, label); + break; + } + + case Jlt: { + Label label = labels[((XirLabel) inst.extra).index]; + emitXirCompare(inst, Condition.LT, ConditionFlag.less, operands, label); + break; + } + + case Jlteq: { + Label label = labels[((XirLabel) inst.extra).index]; + emitXirCompare(inst, Condition.LE, ConditionFlag.lessEqual, operands, label); + break; + } + + case Jbset: { + Label label = labels[((XirLabel) inst.extra).index]; + CiValue pointer = operands[inst.x().index]; + CiValue offset = operands[inst.y().index]; + CiValue bit = operands[inst.z().index]; + assert offset.isConstant() && bit.isConstant(); + CiConstant constantOffset = (CiConstant) offset; + CiConstant constantBit = (CiConstant) bit; + CiAddress src = new CiAddress(inst.kind, pointer, constantOffset.asInt()); + masm.btli(src, constantBit.asInt()); + masm.jcc(ConditionFlag.aboveEqual, label); + break; + } + + case Bind: { + XirLabel l = (XirLabel) inst.extra; + Label label = labels[l.index]; + asm.bind(label); + break; + } + case Safepoint: { + assert info != null : "Must have debug info in order to create a safepoint."; + tasm.recordSafepoint(codePos(), info); + break; + } + case NullCheck: { + tasm.recordImplicitException(codePos(), info); + CiValue pointer = operands[inst.x().index]; + masm.nullCheck(pointer.asRegister()); + break; + } + case Align: { + masm.align((Integer) inst.extra); + break; + } + case StackOverflowCheck: { + int frameSize = initialFrameSizeInBytes(); + int lastFramePage = frameSize / target.pageSize; + // emit multiple stack bangs for methods with frames larger than a page + for (int i = 0; i <= lastFramePage; i++) { + int offset = (i + C1XOptions.StackShadowPages) * target.pageSize; + // Deduct 'frameSize' to handle frames larger than the shadow + bangStackWithOffset(offset - frameSize); + } + break; + } + case PushFrame: { + int frameSize = initialFrameSizeInBytes(); + masm.decrementq(AMD64.rsp, frameSize); // does not emit code for frameSize == 0 + if (C1XOptions.ZapStackOnMethodEntry) { + final int intSize = 4; + for (int i = 0; i < frameSize / intSize; ++i) { + masm.movl(new CiAddress(CiKind.Int, AMD64.rsp.asValue(), i * intSize), 0xC1C1C1C1); + } + } + CiCalleeSaveArea csa = compilation.registerConfig.getCalleeSaveArea(); + if (csa.size != 0) { + int frameToCSA = frameMap.offsetToCalleeSaveAreaStart(); + assert frameToCSA >= 0; + masm.save(csa, frameToCSA); + } + break; + } + case PopFrame: { + int frameSize = initialFrameSizeInBytes(); + + CiCalleeSaveArea csa = compilation.registerConfig.getCalleeSaveArea(); + if (csa.size != 0) { + registerRestoreEpilogueOffset = masm.codeBuffer.position(); + // saved all registers, restore all registers + int frameToCSA = frameMap.offsetToCalleeSaveAreaStart(); + masm.restore(csa, frameToCSA); + } + + masm.incrementq(AMD64.rsp, frameSize); + break; + } + case Push: { + CiRegisterValue value = assureInRegister(operands[inst.x().index]); + masm.push(value.asRegister()); + break; + } + case Pop: { + CiValue result = operands[inst.result.index]; + if (result.isRegister()) { + masm.pop(result.asRegister()); + } else { + masm.pop(rscratch1); + moveOp(rscratch1.asValue(), result, result.kind, null, true); + } + break; + } + case Mark: { + XirMark xmark = (XirMark) inst.extra; + Mark[] references = new Mark[xmark.references.length]; + for (int i = 0; i < references.length; i++) { + references[i] = marks.get(xmark.references[i]); + assert references[i] != null; + } + Mark mark = tasm.recordMark(xmark.id, references); + marks.put(xmark, mark); + break; + } + case Nop: { + for (int i = 0; i < (Integer) inst.extra; i++) { + masm.nop(); + } + break; + } + case RawBytes: { + for (byte b : (byte[]) inst.extra) { + masm.codeBuffer.emitByte(b & 0xff); + } + break; + } + case ShouldNotReachHere: { + if (inst.extra == null) { + stop("should not reach here"); + } else { + stop("should not reach here: " + inst.extra); + } + break; + } + default: + assert false : "Unknown XIR operation " + inst.op; + } + } + } + + /** + * @param offset the offset RSP at which to bang. Note that this offset is relative to RSP after RSP has been + * adjusted to allocated the frame for the method. It denotes an offset "down" the stack. + * For very large frames, this means that the offset may actually be negative (i.e. denoting + * a slot "up" the stack above RSP). + */ + private void bangStackWithOffset(int offset) { + masm.movq(new CiAddress(CiKind.Word, AMD64.RSP, -offset), AMD64.rax); + } + + private CiRegisterValue assureInRegister(CiValue pointer) { + if (pointer.isConstant()) { + CiRegisterValue register = rscratch1.asValue(pointer.kind); + moveOp(pointer, register, pointer.kind, null, false); + return register; + } + + assert pointer.isRegister() : "should be register, but is: " + pointer; + return (CiRegisterValue) pointer; + } + + private void emitXirCompare(XirInstruction inst, Condition condition, ConditionFlag cflag, CiValue[] ops, Label label) { + CiValue x = ops[inst.x().index]; + CiValue y = ops[inst.y().index]; + emitCompare(condition, x, y, null); + masm.jcc(cflag, label); + } + + @Override + public void emitDeoptizationStub(DeoptimizationStub stub) { + masm.bind(stub.label); + directCall(CiRuntimeCall.Deoptimize, stub.info); + shouldNotReachHere(); + } + + public GlobalStub lookupGlobalStub(XirTemplate template) { + return compilation.compiler.lookupGlobalStub(template); + } + + public void callGlobalStub(XirTemplate stub, LIRDebugInfo info, CiRegister result, CiValue... args) { + callGlobalStubHelper(lookupGlobalStub(stub), stub.resultOperand.kind, info, result, args); + } + + public void callGlobalStub(GlobalStub stub, LIRDebugInfo info, CiRegister result, CiValue... args) { + callGlobalStubHelper(stub, stub.resultKind, info, result, args); + } + + private void callGlobalStubHelper(GlobalStub stub, CiKind resultKind, LIRDebugInfo info, CiRegister result, CiValue... args) { + assert args.length == stub.argOffsets.length; + + for (int i = 0; i < args.length; i++) { + storeParameter(args[i], stub.argOffsets[i]); + } + + directCall(stub.stubObject, info); + + if (result != CiRegister.None) { + loadResult(result, stub.resultOffset, resultKind); + } + + // Clear out parameters + if (C1XOptions.GenAssertionCode) { + for (int i = 0; i < args.length; i++) { + masm.movptr(new CiAddress(CiKind.Word, AMD64.RSP, stub.argOffsets[i]), 0); + } + } + } + + private void loadResult(CiRegister r, int offset, CiKind kind) { + if (kind == CiKind.Int || kind == CiKind.Boolean) { + masm.movl(r, new CiAddress(CiKind.Int, AMD64.RSP, offset)); + } else if (kind == CiKind.Float) { + masm.movss(r, new CiAddress(CiKind.Float, AMD64.RSP, offset)); + } else if (kind == CiKind.Double) { + masm.movsd(r, new CiAddress(CiKind.Double, AMD64.RSP, offset)); + } else { + masm.movq(r, new CiAddress(CiKind.Word, AMD64.RSP, offset)); + } + } + + private void storeParameter(CiValue registerOrConstant, int offset) { + CiKind k = registerOrConstant.kind; + if (registerOrConstant.isConstant()) { + CiConstant c = (CiConstant) registerOrConstant; + if (c.kind == CiKind.Object) { + movoop(new CiAddress(CiKind.Word, AMD64.RSP, offset), c); + } else { + masm.movptr(new CiAddress(CiKind.Word, AMD64.RSP, offset), c.asInt()); + } + } else if (registerOrConstant.isRegister()) { + if (k.isFloat()) { + masm.movss(new CiAddress(CiKind.Float, AMD64.RSP, offset), registerOrConstant.asRegister()); + } else if (k.isDouble()) { + masm.movsd(new CiAddress(CiKind.Double, AMD64.RSP, offset), registerOrConstant.asRegister()); + } else { + masm.movq(new CiAddress(CiKind.Word, AMD64.RSP, offset), registerOrConstant.asRegister()); + } + } else { + throw new InternalError("should not reach here"); + } + } + + public void movoop(CiRegister dst, CiConstant obj) { + assert obj.kind == CiKind.Object; + if (obj.isNull()) { + masm.xorq(dst, dst); + } else { + if (target.inlineObjects) { + tasm.recordDataReferenceInCode(obj); + masm.movq(dst, 0xDEADDEADDEADDEADL); + } else { + masm.movq(dst, tasm.recordDataReferenceInCode(obj)); + } + } + } + + public void movoop(CiAddress dst, CiConstant obj) { + movoop(rscratch1, obj); + masm.movq(dst, rscratch1); + } + + public void directCall(Object target, LIRDebugInfo info) { + int before = masm.codeBuffer.position(); + masm.call(); + int after = masm.codeBuffer.position(); + tasm.recordDirectCall(before, after, target, info); + tasm.recordExceptionHandlers(after, info); + } + + public void directJmp(Object target) { + int before = masm.codeBuffer.position(); + masm.jmp(0, true); + int after = masm.codeBuffer.position(); + tasm.recordDirectCall(before, after, target, null); + } + + public void indirectCall(CiRegister dst, Object target, LIRDebugInfo info) { + int before = masm.codeBuffer.position(); + masm.call(dst); + int after = masm.codeBuffer.position(); + tasm.recordIndirectCall(before, after, target, info); + tasm.recordExceptionHandlers(after, info); + } + + protected void stop(String msg) { + if (C1XOptions.GenAssertionCode) { + // TODO: pass a pointer to the message + directCall(CiRuntimeCall.Debug, null); + masm.hlt(); + } + } + + public void shouldNotReachHere() { + stop("should not reach here"); + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64LIRGenerator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64LIRGenerator.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,559 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.max.graal.compiler.target.amd64; + +import com.oracle.max.asm.*; +import com.oracle.max.asm.target.amd64.*; +import com.oracle.max.graal.compiler.*; +import com.oracle.max.graal.compiler.gen.*; +import com.oracle.max.graal.compiler.globalstub.*; +import com.oracle.max.graal.compiler.ir.*; +import com.oracle.max.graal.compiler.lir.*; +import com.oracle.max.graal.compiler.util.*; +import com.sun.cri.bytecode.*; +import com.sun.cri.ci.*; +import com.sun.cri.ri.*; +import com.sun.cri.ri.RiType.*; +import com.sun.cri.xir.*; + +/** + * This class implements the X86-specific portion of the LIR generator. + */ +public class AMD64LIRGenerator extends LIRGenerator { + + private static final CiRegisterValue RAX_I = AMD64.rax.asValue(CiKind.Int); + private static final CiRegisterValue RAX_L = AMD64.rax.asValue(CiKind.Long); + private static final CiRegisterValue RAX_W = AMD64.rax.asValue(CiKind.Word); + private static final CiRegisterValue RDX_I = AMD64.rdx.asValue(CiKind.Int); + private static final CiRegisterValue RDX_L = AMD64.rdx.asValue(CiKind.Long); + + private static final CiRegisterValue LDIV_TMP = RDX_L; + + + /** + * The register in which MUL puts the result for 64-bit multiplication. + */ + private static final CiRegisterValue LMUL_OUT = RAX_L; + + private static final CiRegisterValue SHIFT_COUNT_IN = AMD64.rcx.asValue(CiKind.Int); + + protected static final CiValue ILLEGAL = CiValue.IllegalValue; + + public AMD64LIRGenerator(C1XCompilation compilation) { + super(compilation); + } + + @Override + protected boolean canStoreAsConstant(Value v, CiKind kind) { + if (kind == CiKind.Short || kind == CiKind.Char) { + // there is no immediate move of word values in asemblerI486.?pp + return false; + } + return v instanceof Constant; + } + + @Override + protected boolean canInlineAsConstant(Value v) { + if (v.kind == CiKind.Long) { + if (v.isConstant() && NumUtil.isInt(v.asConstant().asLong())) { + return true; + } + return false; + } + return v.kind != CiKind.Object || v.isNullConstant(); + } + + @Override + protected CiAddress genAddress(CiValue base, CiValue index, int shift, int disp, CiKind kind) { + assert base.isVariableOrRegister(); + if (index.isConstant()) { + return new CiAddress(kind, base, (((CiConstant) index).asInt() << shift) + disp); + } else { + assert index.isVariableOrRegister(); + return new CiAddress(kind, base, (index), CiAddress.Scale.fromShift(shift), disp); + } + } + + @Override + protected void genCmpMemInt(Condition condition, CiValue base, int disp, int c, LIRDebugInfo info) { + lir.cmpMemInt(condition, base, disp, c, info); + } + + @Override + protected void genCmpRegMem(Condition condition, CiValue reg, CiValue base, int disp, CiKind kind, LIRDebugInfo info) { + lir.cmpRegMem(condition, reg, new CiAddress(kind, base, disp), info); + } + + @Override + protected boolean strengthReduceMultiply(CiValue left, int c, CiValue result, CiValue tmp) { + if (tmp.isLegal()) { + if (CiUtil.isPowerOf2(c + 1)) { + lir.move(left, tmp); + lir.shiftLeft(left, CiUtil.log2(c + 1), left); + lir.sub(left, tmp, result); + return true; + } else if (CiUtil.isPowerOf2(c - 1)) { + lir.move(left, tmp); + lir.shiftLeft(left, CiUtil.log2(c - 1), left); + lir.add(left, tmp, result); + return true; + } + } + return false; + } + + @Override + public void visitNegate(Negate x) { + LIRItem value = new LIRItem(x.x(), this); + value.setDestroysRegister(); + value.loadItem(); + CiVariable reg = newVariable(x.kind); + GlobalStub globalStub = null; + if (x.kind == CiKind.Float) { + globalStub = stubFor(GlobalStub.Id.fneg); + } else if (x.kind == CiKind.Double) { + globalStub = stubFor(GlobalStub.Id.dneg); + } + lir.negate(value.result(), reg, globalStub); + setResult(x, reg); + } + + public boolean livesLonger(Value x, Value y) { + // TODO(tw): Estimate which value will live longer. + return false; + } + + public void visitArithmeticOpFloat(Arithmetic x) { + LIRItem left = new LIRItem(x.x(), this); + LIRItem right = new LIRItem(x.y(), this); + assert !left.isStack() || !right.isStack() : "can't both be memory operands"; + boolean mustLoadBoth = x.opcode == Bytecodes.FREM || x.opcode == Bytecodes.DREM; + + // Both are in register, swap operands such that the short-living one is on the left side. + if (x.isCommutative() && left.isRegisterOrVariable() && right.isRegisterOrVariable()) { + if (livesLonger(x.x(), x.y())) { + LIRItem tmp = left; + left = right; + right = tmp; + } + } + + if (left.isRegisterOrVariable() || x.x().isConstant() || mustLoadBoth) { + left.loadItem(); + } + + if (mustLoadBoth) { + // frem and drem destroy also right operand, so move it to a new register + right.setDestroysRegister(); + right.loadItem(); + } else if (right.isRegisterOrVariable()) { + right.loadItem(); + } + + CiVariable reg; + + if (x.opcode == Bytecodes.FREM) { + reg = callRuntimeWithResult(CiRuntimeCall.ArithmeticFrem, null, left.result(), right.result()); + } else if (x.opcode == Bytecodes.DREM) { + reg = callRuntimeWithResult(CiRuntimeCall.ArithmeticDrem, null, left.result(), right.result()); + } else { + reg = newVariable(x.kind); + arithmeticOpFpu(x.opcode, reg, left.result(), right.result(), ILLEGAL); + } + + setResult(x, reg); + } + + public void visitArithmeticOpLong(Arithmetic x) { + int opcode = x.opcode; + if (opcode == Bytecodes.LDIV || opcode == Bytecodes.LREM) { + // emit inline 64-bit code + LIRDebugInfo info = stateFor(x); + CiValue dividend = force(x.x(), RAX_L); // dividend must be in RAX + CiValue divisor = load(x.y()); // divisor can be in any (other) register + + CiValue result = createResultVariable(x); + CiValue resultReg; + if (opcode == Bytecodes.LREM) { + resultReg = RDX_L; // remainder result is produced in rdx + lir.lrem(dividend, divisor, resultReg, LDIV_TMP, info); + } else { + resultReg = RAX_L; // division result is produced in rax + lir.ldiv(dividend, divisor, resultReg, LDIV_TMP, info); + } + + lir.move(resultReg, result); + } else if (opcode == Bytecodes.LMUL) { + LIRItem right = new LIRItem(x.y(), this); + + // right register is destroyed by the long mul, so it must be + // copied to a new register. + right.setDestroysRegister(); + + CiValue left = load(x.x()); + right.loadItem(); + + arithmeticOpLong(opcode, LMUL_OUT, left, right.result(), null); + CiValue result = createResultVariable(x); + lir.move(LMUL_OUT, result); + } else { + LIRItem right = new LIRItem(x.y(), this); + + CiValue left = load(x.x()); + // don't load constants to save register + right.loadNonconstant(); + createResultVariable(x); + arithmeticOpLong(opcode, x.operand(), left, right.result(), null); + } + } + + public void visitArithmeticOpInt(Arithmetic x) { + int opcode = x.opcode; + if (opcode == Bytecodes.IDIV || opcode == Bytecodes.IREM) { + // emit code for integer division or modulus + + // Call 'stateFor' before 'force()' because 'stateFor()' may + // force the evaluation of other instructions that are needed for + // correct debug info. Otherwise the live range of the fixed + // register might be too long. + LIRDebugInfo info = stateFor(x); + + CiValue dividend = force(x.x(), RAX_I); // dividend must be in RAX + CiValue divisor = load(x.y()); // divisor can be in any (other) register + + // idiv and irem use rdx in their implementation so the + // register allocator must not assign it to an interval that overlaps + // this division instruction. + CiRegisterValue tmp = RDX_I; + + CiValue result = createResultVariable(x); + CiValue resultReg; + if (opcode == Bytecodes.IREM) { + resultReg = tmp; // remainder result is produced in rdx + lir.irem(dividend, divisor, resultReg, tmp, info); + } else { + resultReg = RAX_I; // division result is produced in rax + lir.idiv(dividend, divisor, resultReg, tmp, info); + } + + lir.move(resultReg, result); + } else { + // emit code for other integer operations + LIRItem left = new LIRItem(x.x(), this); + LIRItem right = new LIRItem(x.y(), this); + LIRItem leftArg = left; + LIRItem rightArg = right; + if (x.isCommutative() && left.isStack() && right.isRegisterOrVariable()) { + // swap them if left is real stack (or cached) and right is real register(not cached) + leftArg = right; + rightArg = left; + } + + leftArg.loadItem(); + + // do not need to load right, as we can handle stack and constants + if (opcode == Bytecodes.IMUL) { + // check if we can use shift instead + boolean useConstant = false; + boolean useTmp = false; + if (rightArg.result().isConstant()) { + int iconst = rightArg.instruction.asConstant().asInt(); + if (iconst > 0) { + if (CiUtil.isPowerOf2(iconst)) { + useConstant = true; + } else if (CiUtil.isPowerOf2(iconst - 1) || CiUtil.isPowerOf2(iconst + 1)) { + useConstant = true; + useTmp = true; + } + } + } + if (!useConstant) { + rightArg.loadItem(); + } + CiValue tmp = ILLEGAL; + if (useTmp) { + tmp = newVariable(CiKind.Int); + } + createResultVariable(x); + + arithmeticOpInt(opcode, x.operand(), leftArg.result(), rightArg.result(), tmp); + } else { + createResultVariable(x); + CiValue tmp = ILLEGAL; + arithmeticOpInt(opcode, x.operand(), leftArg.result(), rightArg.result(), tmp); + } + } + } + + public void visitArithmeticOpWord(Arithmetic x) { + int opcode = x.opcode; + if (opcode == Bytecodes.WDIV || opcode == Bytecodes.WREM || opcode == Bytecodes.WDIVI || opcode == Bytecodes.WREMI) { + // emit code for long division or modulus + // emit inline 64-bit code + LIRDebugInfo info = stateFor(x); + CiValue dividend = force(x.x(), RAX_L); // dividend must be in RAX + CiValue divisor = load(x.y()); // divisor can be in any (other) register + + CiValue result = createResultVariable(x); + CiValue resultReg; + if (opcode == Bytecodes.WREM) { + resultReg = RDX_L; // remainder result is produced in rdx + lir.wrem(dividend, divisor, resultReg, LDIV_TMP, info); + } else if (opcode == Bytecodes.WREMI) { + resultReg = RDX_L; // remainder result is produced in rdx + lir.wremi(dividend, divisor, resultReg, LDIV_TMP, info); + } else if (opcode == Bytecodes.WDIV) { + resultReg = RAX_L; // division result is produced in rax + lir.wdiv(dividend, divisor, resultReg, LDIV_TMP, info); + } else { + assert opcode == Bytecodes.WDIVI; + resultReg = RAX_L; // division result is produced in rax + lir.wdivi(dividend, divisor, resultReg, LDIV_TMP, info); + } + + lir.move(resultReg, result); + } else if (opcode == Bytecodes.LMUL) { + LIRItem right = new LIRItem(x.y(), this); + + // right register is destroyed by the long mul, so it must be + // copied to a new register. + right.setDestroysRegister(); + + CiValue left = load(x.x()); + right.loadItem(); + + CiValue reg = LMUL_OUT; + arithmeticOpLong(opcode, reg, left, right.result(), null); + CiValue result = createResultVariable(x); + lir.move(reg, result); + } else { + LIRItem right = new LIRItem(x.y(), this); + + CiValue left = load(x.x()); + // don't load constants to save register + right.loadNonconstant(); + createResultVariable(x); + arithmeticOpLong(opcode, x.operand(), left, right.result(), null); + } + } + + @Override + public void visitArithmetic(Arithmetic x) { + trySwap(x); + + if (x.kind.isWord() || x.opcode == Bytecodes.WREMI) { + visitArithmeticOpWord(x); + return; + } + + assert Util.archKindsEqual(x.x().kind, x.kind) && Util.archKindsEqual(x.y().kind, x.kind) : "wrong parameter types: " + Bytecodes.nameOf(x.opcode); + switch (x.kind) { + case Float: + case Double: + visitArithmeticOpFloat(x); + return; + case Long: + visitArithmeticOpLong(x); + return; + case Int: + visitArithmeticOpInt(x); + return; + } + throw Util.shouldNotReachHere(); + } + + @Override + public void visitShift(Shift x) { + // count must always be in rcx + CiValue count = makeOperand(x.y()); + boolean mustLoadCount = !count.isConstant() || x.kind == CiKind.Long; + if (mustLoadCount) { + // count for long must be in register + count = force(x.y(), SHIFT_COUNT_IN); + } + + CiValue value = load(x.x()); + CiValue reg = createResultVariable(x); + + shiftOp(x.opcode, reg, value, count, ILLEGAL); + } + + @Override + public void visitLogic(Logic x) { + trySwap(x); + + LIRItem right = new LIRItem(x.y(), this); + + CiValue left = load(x.x()); + right.loadNonconstant(); + CiValue reg = createResultVariable(x); + + logicOp(x.opcode, reg, left, right.result()); + } + + private void trySwap(Binary x) { + // (tw) TODO: Check what this is for? + } + + @Override + public void visitMaterialize(NormalizeCompare x) { + LIRItem left = new LIRItem(x.x(), this); + LIRItem right = new LIRItem(x.y(), this); + if (!x.kind.isVoid() && x.x().kind.isLong()) { + left.setDestroysRegister(); + } + left.loadItem(); + right.loadItem(); + + if (x.kind.isVoid()) { + lir.cmp(Condition.TRUE, left.result(), right.result()); + } else if (x.x().kind.isFloat() || x.x().kind.isDouble()) { + CiValue reg = createResultVariable(x); + int code = x.opcode; + lir.fcmp2int(left.result(), right.result(), reg, code == Bytecodes.FCMPL || code == Bytecodes.DCMPL); + } else if (x.x().kind.isLong() || x.x().kind.isWord()) { + CiValue reg = createResultVariable(x); + lir.lcmp2int(left.result(), right.result(), reg); + } else { + assert false; + } + } + + @Override + public void visitConvert(Convert x) { + CiValue input = load(x.value()); + CiVariable result = newVariable(x.kind); + // arguments of lirConvert + GlobalStub globalStub = null; + // Checkstyle: off + switch (x.opcode) { + case Bytecodes.F2I: globalStub = stubFor(GlobalStub.Id.f2i); break; + case Bytecodes.F2L: globalStub = stubFor(GlobalStub.Id.f2l); break; + case Bytecodes.D2I: globalStub = stubFor(GlobalStub.Id.d2i); break; + case Bytecodes.D2L: globalStub = stubFor(GlobalStub.Id.d2l); break; + } + // Checkstyle: on + if (globalStub != null) { + // Force result to be rax to match global stubs expectation. + CiValue stubResult = x.kind == CiKind.Int ? RAX_I : RAX_L; + lir.convert(x.opcode, input, stubResult, globalStub); + lir.move(stubResult, result); + } else { + lir.convert(x.opcode, input, result, globalStub); + } + setResult(x, result); + } + + @Override + public void visitMerge(Merge x) { + // nothing to do for now + } + + @Override + public void visitIf(If x) { + CiKind kind = x.compare().x().kind; + + Condition cond = x.compare().condition(); + + LIRItem xitem = new LIRItem(x.compare().x(), this); + LIRItem yitem = new LIRItem(x.compare().y(), this); + LIRItem xin = xitem; + LIRItem yin = yitem; + + if (kind.isLong()) { + // for longs, only conditions "eql", "neq", "lss", "geq" are valid; + // mirror for other conditions + if (cond == Condition.GT || cond == Condition.LE) { + cond = cond.mirror(); + xin = yitem; + yin = xitem; + } + xin.setDestroysRegister(); + } + xin.loadItem(); + if (kind.isLong() && yin.result().isConstant() && yin.instruction.asConstant().asLong() == 0 && (cond == Condition.EQ || cond == Condition.NE)) { + // dont load item + } else if (kind.isLong() || kind.isFloat() || kind.isDouble()) { + // longs cannot handle constants at right side + yin.loadItem(); + } + + setNoResult(x); + + CiValue left = xin.result(); + CiValue right = yin.result(); + lir.cmp(cond, left, right); + if (x.compare().x().kind.isFloat() || x.compare().x().kind.isDouble()) { + Instruction unorderedSucc = x.falseSuccessor(); + if (x.compare().unorderedIsTrue()) { + unorderedSucc = x.trueSuccessor(); + } + lir.branch(cond, right.kind, getLIRBlock(x.trueSuccessor()), getLIRBlock(unorderedSucc)); + } else { + lir.branch(cond, right.kind, getLIRBlock(x.trueSuccessor())); + } + assert x.defaultSuccessor() == x.falseSuccessor() : "wrong destination above"; + lir.jump(getLIRBlock(x.defaultSuccessor())); + } + + @Override + public void visitExceptionDispatch(ExceptionDispatch x) { + // TODO ls: this needs some more work... + + RiType riType = x.catchType(); + assert riType.isResolved(); + + XirArgument obj = toXirArgument(x.exception()); + XirArgument clazz = toXirArgument(riType.getEncoding(Representation.ObjectHub)); + XirSnippet snippet = xir.genInstanceOf(site(x), obj, clazz, riType); + CiValue result = emitXir(snippet, x, stateFor(x), null, true); + + lir.cmp(Condition.EQ, result, CiConstant.TRUE); + lir.branch(Condition.EQ, CiKind.Boolean, getLIRBlock(x.catchSuccessor())); + + lir.jump(getLIRBlock(x.otherSuccessor())); + } + + @Override + public void visitLoopBegin(LoopBegin x) { + visitMerge(x); + } + + @Override + public void visitLoopEnd(LoopEnd x) { + setNoResult(x); + + // emit phi-instruction moves after safepoint since this simplifies + // describing the state at the safepoint. + + moveToPhi(); + lir.jump(getLIRBlock(x.loopBegin())); + } + + @Override + public void visitValueAnchor(ValueAnchor valueAnchor) { + // nothing to do for ValueAnchors + } + +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64XirAssembler.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64XirAssembler.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,220 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.target.amd64; + +import static com.sun.cri.xir.XirTemplate.GlobalFlags.*; + +import java.util.*; + +import com.oracle.max.asm.target.amd64.*; +import com.sun.cri.ci.*; +import com.sun.cri.xir.*; + +/** + * AMD64 version of {@link CiXirAssembler}. + * + * @author Thomas Wuerthinger + * + */ +public class AMD64XirAssembler extends CiXirAssembler { + + @Override + protected XirTemplate buildTemplate(String name, boolean isStub) { + List fastPath = new ArrayList(instructions.size()); + List slowPath = new ArrayList(); + List calleeTemplates = new ArrayList(); + + int flags = 0; + + if (isStub) { + flags |= GLOBAL_STUB.mask; + } + + List currentList = fastPath; + + XirOperand fixedRDX = null; + XirOperand fixedRAX = null; + XirOperand fixedRCX = null; + XirOperand fixedRSI = null; + XirOperand fixedRDI = null; + HashSet boundLabels = new HashSet(); + + for (XirInstruction i : instructions) { + boolean appended = false; + switch (i.op) { + case Mov: + break; + + case Add: + case Sub: + case Div: + case Mul: + case Mod: + case Shl: + case Shr: + case And: + case Or: + case Xor: + // Convert to two operand form + XirOperand xOp = i.x(); + if (i.op == XirOp.Div || i.op == XirOp.Mod) { + if (fixedRDX == null) { + fixedRDX = createRegisterTemp("divModTemp", CiKind.Int, AMD64.rdx); + } + // Special treatment to make sure that the left input of % and / is in RAX + if (fixedRAX == null) { + fixedRAX = createRegisterTemp("divModLeftInput", CiKind.Int, AMD64.rax); + } + currentList.add(new XirInstruction(i.x().kind, XirOp.Mov, fixedRAX, i.x())); + xOp = fixedRAX; + } else { + if (i.result != i.x()) { + currentList.add(new XirInstruction(i.result.kind, XirOp.Mov, i.result, i.x())); + xOp = i.result; + } + } + + XirOperand yOp = i.y(); + if ((i.op == XirOp.Shl || i.op == XirOp.Shr) && (!(i.y() instanceof XirConstantOperand))) { + // Special treatment to make sure that the shift count is always in RCX + if (fixedRCX == null) { + fixedRCX = createRegisterTemp("fixedShiftCount", i.y().kind, AMD64.rcx); + } + currentList.add(new XirInstruction(i.result.kind, XirOp.Mov, fixedRCX, i.y())); + yOp = fixedRCX; + } else if (i.op == XirOp.Mul && (i.y() instanceof XirConstantOperand)) { + // Cannot multiply directly with a constant, so introduce a new temporary variable + XirOperand tempLocation = createTemp("mulTempLocation", i.y().kind); + currentList.add(new XirInstruction(i.result.kind, XirOp.Mov, tempLocation, i.y())); + yOp = tempLocation; + + } + + if (xOp != i.x() || yOp != i.y()) { + currentList.add(new XirInstruction(i.result.kind, i.op, i.result, xOp, yOp)); + appended = true; + } + break; + + case RepeatMoveWords: + case RepeatMoveBytes: + if (fixedRSI == null) { + fixedRSI = createRegisterTemp("fixedRSI", CiKind.Word, AMD64.rsi); + } + if (fixedRDI == null) { + fixedRDI = createRegisterTemp("fixedRDI", CiKind.Word, AMD64.rdi); + } + if (fixedRCX == null) { + fixedRCX = createRegisterTemp("fixedRCX", CiKind.Word, AMD64.rcx); + } + currentList.add(new XirInstruction(CiKind.Word, XirOp.Mov, fixedRSI, i.x())); + currentList.add(new XirInstruction(CiKind.Word, XirOp.Mov, fixedRDI, i.y())); + currentList.add(new XirInstruction(CiKind.Word, XirOp.Mov, fixedRCX, i.z())); + currentList.add(new XirInstruction(CiKind.Illegal, i.op, i.result, fixedRSI, fixedRDI, fixedRCX)); + appended = true; + break; + + case NullCheck: + case PointerLoad: + case LoadEffectiveAddress: + case PointerStore: + case PointerLoadDisp: + case PointerStoreDisp: + break; + case PointerCAS: + if (fixedRAX == null) { + fixedRAX = createRegisterTemp("fixedRAX", CiKind.Word, AMD64.rax); + } + // x = source of cmpxch + // y = new value + // z = old value (i.e., the one compared to). Must be in RAX (and so must the result). + currentList.add(new XirInstruction(CiKind.Word, XirOp.Mov, fixedRAX, i.z())); + currentList.add(new XirInstruction(i.kind, i.op, i.result, i.x(), i.y(), fixedRAX)); + appended = true; + break; + case CallStub: + flags |= HAS_STUB_CALL.mask; + calleeTemplates.add((XirTemplate) i.extra); + break; + case CallRuntime: + flags |= HAS_RUNTIME_CALL.mask; + break; + case Jmp: + // jmp can be either into the snippet or to a runtime target + flags |= i.extra instanceof XirLabel ? HAS_CONTROL_FLOW.mask : HAS_RUNTIME_CALL.mask; + break; + case Jeq: + case Jneq: + case Jgt: + case Jgteq: + case Jugteq: + case Jlt: + case Jlteq: + case DecAndJumpNotZero: + case Jbset: + flags |= HAS_CONTROL_FLOW.mask; + break; + case Bind: + XirLabel label = (XirLabel) i.extra; + currentList = label.inline ? fastPath : slowPath; + assert !boundLabels.contains(label) : "label may be bound only once"; + boundLabels.add(label); + break; + case Safepoint: + case Align: + case StackOverflowCheck: + case PushFrame: + case PopFrame: + case Push: + case Pop: + case Mark: + case Nop: + case RawBytes: + case ShouldNotReachHere: + break; + default: + assert false : "Unknown XIR operation " + i.op; + } + if (!appended) { + currentList.add(i); + } + } + for (XirLabel label : labels) { + assert boundLabels.contains(label) : "label " + label.name + " is not bound!"; + } + XirInstruction[] fp = fastPath.toArray(new XirInstruction[fastPath.size()]); + XirInstruction[] sp = slowPath.size() > 0 ? slowPath.toArray(new XirInstruction[slowPath.size()]) : null; + XirLabel[] xirLabels = labels.toArray(new XirLabel[labels.size()]); + XirParameter[] xirParameters = parameters.toArray(new XirParameter[parameters.size()]); + XirTemp[] temporaryOperands = temps.toArray(new XirTemp[temps.size()]); + XirConstant[] constantOperands = constants.toArray(new XirConstant[constants.size()]); + XirTemplate[] calleeTemplateArray = calleeTemplates.toArray(new XirTemplate[calleeTemplates.size()]); + XirMark[] marksArray = marks.toArray(new XirMark[marks.size()]); + return new XirTemplate(name, this.variableCount, this.allocateResultOperand, resultOperand, fp, sp, xirLabels, xirParameters, temporaryOperands, constantOperands, flags, calleeTemplateArray, marksArray, outgoingStackSize); + } + + @Override + public CiXirAssembler copy() { + return new AMD64XirAssembler(); + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/util/ArrayMap.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/util/ArrayMap.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.util; + +/** + * The {@code ArrayMap} class implements an efficient one-level map which is implemented + * as an array. Note that because of the one-level array inside, this data structure performs best + * when the range of integer keys is small and densely used. Note that the implementation can + * handle arbitrary intervals, including negative numbers, up to intervals of size 2^31 - 1. + * + * @author Ben L. Titzer + */ +public class ArrayMap { + + private static final int INITIAL_SIZE = 5; // how big the initial array should be + private static final int EXTRA = 2; // how far on the left or right of a new element to grow + + Object[] map; + int low; + + /** + * Constructs a new {@code ArrayMap} with no initial assumptions. + */ + public ArrayMap() { + } + + /** + * Constructs a new {@code ArrayMap} that initially covers the specified interval. + * Note that this map will automatically expand if necessary later. + * @param low the low index, inclusive + * @param high the high index, exclusive + */ + public ArrayMap(int low, int high) { + this.low = low; + this.map = new Object[high - low + 1]; + } + + /** + * Puts a new value in the map at the specified index. + * @param i the index at which to store the value + * @param value the value to store at the specified index + */ + public void put(int i, T value) { + int index = i - low; + if (map == null) { + // no map yet + map = new Object[INITIAL_SIZE]; + low = index - 2; + map[INITIAL_SIZE / 2] = value; + } else if (index < 0) { + // grow backwards + growBackward(i, value); + } else if (index >= map.length) { + // grow forwards + growForward(i, value); + } else { + // no growth necessary + map[index] = value; + } + } + + /** + * Gets the value at the specified index in the map. + * @param i the index + * @return the value at the specified index; {@code null} if there is no value at the specified index, + * or if the index is out of the currently stored range + */ + public T get(int i) { + int index = i - low; + if (map == null || index < 0 || index >= map.length) { + return null; + } + Class type = null; + return Util.uncheckedCast(type, map[index]); + } + + public int length() { + return map.length; + } + + private void growBackward(int i, T value) { + int nlow = i - EXTRA; + Object[] nmap = new Object[low - nlow + map.length]; + System.arraycopy(map, 0, nmap, low - nlow, map.length); + map = nmap; + low = nlow; + map[i - low] = value; + } + + private void growForward(int i, T value) { + int nlen = i - low + 1 + EXTRA; + Object[] nmap = new Object[nlen]; + System.arraycopy(map, 0, nmap, 0, map.length); + map = nmap; + map[i - low] = value; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/util/BitMap2D.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/util/BitMap2D.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.util; + +import com.sun.cri.ci.*; + +/** + * This class implements a two-dimensional bitmap. + * + * @author Marcelo Cintra + * @author Thomas Wuerthinger + */ +public final class BitMap2D { + + private CiBitMap map; + private final int bitsPerSlot; + + private int bitIndex(int slotIndex, int bitWithinSlotIndex) { + return slotIndex * bitsPerSlot + bitWithinSlotIndex; + } + + private boolean verifyBitWithinSlotIndex(int index) { + assert index < bitsPerSlot : "index " + index + " is out of bounds " + bitsPerSlot; + return true; + } + + public BitMap2D(int sizeInSlots, int bitsPerSlot) { + map = new CiBitMap(sizeInSlots * bitsPerSlot); + this.bitsPerSlot = bitsPerSlot; + } + + public int sizeInBits() { + return map.size(); + } + + // Returns number of full slots that have been allocated + public int sizeInSlots() { + return map.size() / bitsPerSlot; + } + + public boolean isValidIndex(int slotIndex, int bitWithinSlotIndex) { + assert verifyBitWithinSlotIndex(bitWithinSlotIndex); + return (bitIndex(slotIndex, bitWithinSlotIndex) < sizeInBits()); + } + + public boolean at(int slotIndex, int bitWithinSlotIndex) { + assert verifyBitWithinSlotIndex(bitWithinSlotIndex); + return map.get(bitIndex(slotIndex, bitWithinSlotIndex)); + } + + public void setBit(int slotIndex, int bitWithinSlotIndex) { + assert verifyBitWithinSlotIndex(bitWithinSlotIndex); + map.set(bitIndex(slotIndex, bitWithinSlotIndex)); + } + + public void clearBit(int slotIndex, int bitWithinSlotIndex) { + assert verifyBitWithinSlotIndex(bitWithinSlotIndex); + map.clear(bitIndex(slotIndex, bitWithinSlotIndex)); + } + + public void atPutGrow(int slotIndex, int bitWithinSlotIndex, boolean value) { + int size = sizeInSlots(); + if (size <= slotIndex) { + while (size <= slotIndex) { + size *= 2; + } + CiBitMap newBitMap = new CiBitMap(size * bitsPerSlot); + newBitMap.setUnion(map); + map = newBitMap; + } + + if (value) { + setBit(slotIndex, bitWithinSlotIndex); + } else { + clearBit(slotIndex, bitWithinSlotIndex); + } + } + + public void clear() { + map.clearAll(); + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/util/BlockWorkList.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/util/BlockWorkList.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2009, 2009, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.util; + +import com.oracle.max.graal.compiler.ir.*; + +/** + * This class implements a worklist for dealing with blocks. The worklist can + * operate either as a stack (i.e. first-in / last-out), or as a sorted list, + * where blocks can be sorted by a supplied number. The latter usage lends itself + * naturally to iterative dataflow analysis problems. + * + * This implementation is not able to tell if a block is in the worklist already. + * Note that this implementation is slightly less efficient than the dedicated + * work list in {@link com.oracle.max.graal.compiler.graph.ScopeData}, because this worklist uses + * an externally supplied number. + * + * @author Ben L. Titzer + */ +public class BlockWorkList { + Merge[] workList; + int[] workListNumbers; + int workListIndex; + + /** + * Adds a block to this list in an unsorted fashion, like a stack. + * @param block the block to add + */ + public void add(Merge block) { + if (workList == null) { + // worklist not allocated yet + allocate(); + } else if (workListIndex == workList.length) { + // need to grow the worklist + grow(); + } + // put the block at the end of the array + workList[workListIndex++] = block; + } + + /** + * Adds a block to this list, sorted by the supplied number. The block + * with the lowest number is returned upon subsequent removes. + * @param block the block to add + * @param number the number used to sort the block + */ + public void addSorted(Merge block, int number) { + if (workList == null) { + // worklist not allocated yet + allocate(); + } else if (workListIndex == workList.length) { + // need to grow the worklist + grow(); + } + // put the block at the end of the array + workList[workListIndex] = block; + workListNumbers[workListIndex] = number; + workListIndex++; + int i = workListIndex - 2; + // push block towards the beginning of the array + for (; i >= 0; i--) { + int n = workListNumbers[i]; + if (n >= number) { + break; // already in the right position + } + workList[i + 1] = workList[i]; // bubble b down by one + workList[i] = block; // and overwrite its place with block + workListNumbers[i + 1] = n; // bubble n down by one + workListNumbers[i] = number; // and overwrite its place with number + } + } + + /** + * Removes the next block from this work list. If the blocks have been added + * in a sorted order, then the block with the lowest number is returned. Otherwise, + * the last block added is returned. + * @return the next block in the list + */ + public Merge removeFromWorkList() { + if (workListIndex != 0) { + return workList[--workListIndex]; + } + return null; + } + + /** + * Checks whether the list is empty. + * @return {@code true} if this list is empty + */ + public boolean isEmpty() { + return workListIndex == 0; + } + + private void allocate() { + workList = new Merge[5]; + workListNumbers = new int[5]; + } + + private void grow() { + int prevLength = workList.length; + Merge[] nworkList = new Merge[prevLength * 3]; + System.arraycopy(workList, 0, nworkList, 0, prevLength); + workList = nworkList; + + int[] nworkListNumbers = new int[prevLength * 3]; + System.arraycopy(workListNumbers, 0, nworkListNumbers, 0, prevLength); + workListNumbers = nworkListNumbers; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/util/IntList.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/util/IntList.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2010, 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.util; + +import java.util.*; + +/** + * An expandable and indexable list of {@code int}s. + * + * This class avoids the boxing/unboxing incurred by {@code ArrayList}. + * + * @author Doug Simon + */ +public final class IntList { + + private int[] array; + private int size; + + /** + * Creates an int list with a specified initial capacity. + * + * @param initialCapacity + */ + public IntList(int initialCapacity) { + array = new int[initialCapacity]; + } + + /** + * Creates an int list with a specified initial array. + * + * @param array the initial array used for the list (no copy is made) + * @param initialSize the initial {@linkplain #size() size} of the list (must be less than or equal to {@code array.length} + */ + public IntList(int[] array, int initialSize) { + assert initialSize <= array.length; + this.array = array; + this.size = initialSize; + } + + /** + * Makes a new int list by copying a range from a given int list. + * + * @param other the list from which a range of values is to be copied into the new list + * @param startIndex the index in {@code other} at which to start copying + * @param length the number of values to copy from {@code other} + * @return a new int list whose {@linkplain #size() size} and capacity is {@code length} + */ + public static IntList copy(IntList other, int startIndex, int length) { + return copy(other, startIndex, length, length); + } + + /** + * Makes a new int list by copying a range from a given int list. + * + * @param other the list from which a range of values is to be copied into the new list + * @param startIndex the index in {@code other} at which to start copying + * @param length the number of values to copy from {@code other} + * @param initialCapacity the initial capacity of the new int list (must be greater or equal to {@code length}) + * @return a new int list whose {@linkplain #size() size} is {@code length} + */ + public static IntList copy(IntList other, int startIndex, int length, int initialCapacity) { + assert initialCapacity >= length : "initialCapacity < length"; + int[] array = new int[initialCapacity]; + System.arraycopy(other.array, startIndex, array, 0, length); + return new IntList(array, length); + } + + public int size() { + return size; + } + + /** + * Appends a value to the end of this list, increasing its {@linkplain #size() size} by 1. + * + * @param value the value to append + */ + public void add(int value) { + if (size == array.length) { + int newSize = (size * 3) / 2 + 1; + array = Arrays.copyOf(array, newSize); + } + array[size++] = value; + } + + /** + * Gets the value in this list at a given index. + * + * @param index the index of the element to return + * @throws IndexOutOfBoundsException if {@code index < 0 || index >= size()} + */ + public int get(int index) { + if (index >= size) { + throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size); + } + return array[index]; + } + + /** + * Sets the size of this list to 0. + */ + public void clear() { + size = 0; + } + + /** + * Sets a value at a given index in this list. + * + * @param index the index of the element to update + * @param value the new value of the element + * @throws IndexOutOfBoundsException if {@code index < 0 || index >= size()} + */ + public void set(int index, int value) { + if (index >= size) { + throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size); + } + array[index] = value; + } + + /** + * Adjusts the {@linkplain #size() size} of this int list. + * + * If {@code newSize < size()}, the size is changed to {@code newSize}. + * If {@code newSize > size()}, sufficient 0 elements are {@linkplain #add(int) added} + * until {@code size() == newSize}. + * + * @param newSize the new size of this int list + */ + public void setSize(int newSize) { + if (newSize < size) { + size = newSize; + } else if (newSize > size) { + array = Arrays.copyOf(array, newSize); + } + } + + @Override + public String toString() { + if (array.length == size) { + return Arrays.toString(array); + } + return Arrays.toString(Arrays.copyOf(array, size)); + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/util/Util.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/util/Util.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,427 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.util; + +import java.util.*; + +import com.oracle.max.graal.compiler.*; +import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.compiler.ir.*; +import com.sun.cri.ci.*; +import com.sun.cri.ri.*; + +/** + * The {@code Util} class contains a motley collection of utility methods used throughout the compiler. + * + * @author Ben L. Titzer + * @author Doug Simon + */ +public class Util { + + public static final int PRINTING_LINE_WIDTH = 40; + public static final char SECTION_CHARACTER = '*'; + public static final char SUB_SECTION_CHARACTER = '='; + public static final char SEPERATOR_CHARACTER = '-'; + + public static RuntimeException unimplemented() { + throw new InternalError("unimplemented"); + } + + public static RuntimeException unimplemented(String msg) { + throw new InternalError("unimplemented:" + msg); + } + + public static RuntimeException shouldNotReachHere() { + throw new InternalError("should not reach here"); + } + + public static RuntimeException shouldNotReachHere(String msg) { + throw new InternalError("Should not reach here: " + msg); + } + + public static boolean replaceInList(T a, T b, List list) { + final int max = list.size(); + for (int i = 0; i < max; i++) { + if (list.get(i) == a) { + list.set(i, b); + return true; + } + } + return false; + } + + public static boolean replaceAllInList(T a, T b, List list) { + final int max = list.size(); + for (int i = 0; i < max; i++) { + if (list.get(i) == a) { + list.set(i, b); + } + } + return false; + } + + /** + * Statically cast an object to an arbitrary Object type. Dynamically checked. + */ + @SuppressWarnings("unchecked") + public static T uncheckedCast(Class type, Object object) { + return (T) object; + } + + /** + * Statically cast an object to an arbitrary Object type. Dynamically checked. + */ + @SuppressWarnings("unchecked") + public static T uncheckedCast(Object object) { + return (T) object; + } + + /** + * Utility method to combine a base hash with the identity hash of one or more objects. + * + * @param hash the base hash + * @param x the object to add to the hash + * @return the combined hash + */ + public static int hash1(int hash, Object x) { + // always set at least one bit in case the hash wraps to zero + return 0x10000000 | (hash + 7 * System.identityHashCode(x)); + } + + /** + * Utility method to combine a base hash with the identity hash of one or more objects. + * + * @param hash the base hash + * @param x the first object to add to the hash + * @param y the second object to add to the hash + * @return the combined hash + */ + public static int hash2(int hash, Object x, Object y) { + // always set at least one bit in case the hash wraps to zero + return 0x20000000 | (hash + 7 * System.identityHashCode(x) + 11 * System.identityHashCode(y)); + } + + /** + * Utility method to combine a base hash with the identity hash of one or more objects. + * + * @param hash the base hash + * @param x the first object to add to the hash + * @param y the second object to add to the hash + * @param z the third object to add to the hash + * @return the combined hash + */ + public static int hash3(int hash, Object x, Object y, Object z) { + // always set at least one bit in case the hash wraps to zero + return 0x30000000 | (hash + 7 * System.identityHashCode(x) + 11 * System.identityHashCode(y) + 13 * System.identityHashCode(z)); + } + + /** + * Utility method to combine a base hash with the identity hash of one or more objects. + * + * @param hash the base hash + * @param x the first object to add to the hash + * @param y the second object to add to the hash + * @param z the third object to add to the hash + * @param w the fourth object to add to the hash + * @return the combined hash + */ + public static int hash4(int hash, Object x, Object y, Object z, Object w) { + // always set at least one bit in case the hash wraps to zero + return 0x40000000 | (hash + 7 * System.identityHashCode(x) + 11 * System.identityHashCode(y) + 13 * System.identityHashCode(z) + 17 * System.identityHashCode(w)); + } + + static { + assert CiUtil.log2(2) == 1; + assert CiUtil.log2(4) == 2; + assert CiUtil.log2(8) == 3; + assert CiUtil.log2(16) == 4; + assert CiUtil.log2(32) == 5; + assert CiUtil.log2(0x40000000) == 30; + + assert CiUtil.log2(2L) == 1; + assert CiUtil.log2(4L) == 2; + assert CiUtil.log2(8L) == 3; + assert CiUtil.log2(16L) == 4; + assert CiUtil.log2(32L) == 5; + assert CiUtil.log2(0x4000000000000000L) == 62; + + assert !CiUtil.isPowerOf2(3); + assert !CiUtil.isPowerOf2(5); + assert !CiUtil.isPowerOf2(7); + assert !CiUtil.isPowerOf2(-1); + + assert CiUtil.isPowerOf2(2); + assert CiUtil.isPowerOf2(4); + assert CiUtil.isPowerOf2(8); + assert CiUtil.isPowerOf2(16); + assert CiUtil.isPowerOf2(32); + assert CiUtil.isPowerOf2(64); + } + + /** + * Sets the element at a given position of a list and ensures that this position exists. If the list is current + * shorter than the position, intermediate positions are filled with a given value. + * + * @param list the list to put the element into + * @param pos the position at which to insert the element + * @param x the element that should be inserted + * @param filler the filler element that is used for the intermediate positions in case the list is shorter than pos + */ + public static void atPutGrow(List list, int pos, T x, T filler) { + if (list.size() < pos + 1) { + while (list.size() < pos + 1) { + list.add(filler); + } + assert list.size() == pos + 1; + } + + assert list.size() >= pos + 1; + list.set(pos, x); + } + + public static void breakpoint() { + // do nothing. + } + + public static void guarantee(boolean b, String string) { + if (!b) { + throw new CiBailout(string); + } + } + + public static void warning(String string) { + TTY.println("WARNING: " + string); + } + + public static int safeToInt(long l) { + assert (int) l == l; + return (int) l; + } + + public static int roundUp(int number, int mod) { + return ((number + mod - 1) / mod) * mod; + } + + public static void truncate(List list, int length) { + while (list.size() > length) { + list.remove(list.size() - 1); + } + } + + public static void printSection(String name, char sectionCharacter) { + + String header = " " + name + " "; + int remainingCharacters = PRINTING_LINE_WIDTH - header.length(); + int leftPart = remainingCharacters / 2; + int rightPart = remainingCharacters - leftPart; + for (int i = 0; i < leftPart; i++) { + TTY.print(sectionCharacter); + } + + TTY.print(header); + + for (int i = 0; i < rightPart; i++) { + TTY.print(sectionCharacter); + } + + TTY.println(); + } + + /** + * Prints entries in a byte array as space separated hex values to {@link TTY}. + * + * @param address an address at which the bytes are located. This is used to print an address prefix per line of output. + * @param array the array containing all the bytes to print + * @param bytesPerLine the number of values to print per line of output + */ + public static void printBytes(long address, byte[] array, int bytesPerLine) { + printBytes(address, array, 0, array.length, bytesPerLine); + } + + /** + * Prints entries in a byte array as space separated hex values to {@link TTY}. + * + * @param address an address at which the bytes are located. This is used to print an address prefix per line of output. + * @param array the array containing the bytes to print + * @param offset the offset in {@code array} of the values to print + * @param length the number of values from {@code array} print + * @param bytesPerLine the number of values to print per line of output + */ + public static void printBytes(long address, byte[] array, int offset, int length, int bytesPerLine) { + assert bytesPerLine > 0; + boolean newLine = true; + for (int i = 0; i < length; i++) { + if (newLine) { + TTY.print("%08x: ", address + i); + newLine = false; + } + TTY.print("%02x ", array[i]); + if (i % bytesPerLine == bytesPerLine - 1) { + TTY.println(); + newLine = true; + } + } + + if (length % bytesPerLine != bytesPerLine) { + TTY.println(); + } + } + + public static CiKind[] signatureToKinds(RiSignature signature, CiKind receiverKind) { + int args = signature.argumentCount(false); + CiKind[] result; + int i = 0; + if (receiverKind != null) { + result = new CiKind[args + 1]; + result[0] = receiverKind; + i = 1; + } else { + result = new CiKind[args]; + } + for (int j = 0; j < args; j++) { + result[i + j] = signature.argumentKindAt(j); + } + return result; + } + + public static boolean isShiftCount(int x) { + return 0 <= x && x < 32; + } + + /** + * Determines if a given {@code int} value is the range of unsigned byte values. + */ + public static boolean isUByte(int x) { + return (x & 0xff) == x; + } + + /** + * Determines if a given {@code int} value is the range of signed byte values. + */ + public static boolean isByte(int x) { + return (byte) x == x; + } + + /** + * Determines if a given {@code long} value is the range of unsigned byte values. + */ + public static boolean isUByte(long x) { + return (x & 0xffL) == x; + } + + /** + * Determines if a given {@code long} value is the range of signed byte values. + */ + public static boolean isByte(long l) { + return (byte) l == l; + } + + /** + * Determines if a given {@code long} value is the range of unsigned int values. + */ + public static boolean isUInt(long x) { + return (x & 0xffffffffL) == x; + } + + /** + * Determines if a given {@code long} value is the range of signed int values. + */ + public static boolean isInt(long l) { + return (int) l == l; + } + /** + * Determines if a given {@code int} value is the range of signed short values. + */ + public static boolean isShort(int x) { + return (short) x == x; + } + + public static boolean is32bit(long x) { + return -0x80000000L <= x && x < 0x80000000L; + } + + public static short safeToShort(int v) { + assert isShort(v); + return (short) v; + } + + /** + * Determines if the kinds of two given IR nodes are equal at the {@linkplain #archKind(CiKind) architecture} + * level in the context of the {@linkplain C1XCompilation#compilation()} compilation. + */ + public static boolean archKindsEqual(Value i, Value other) { + return archKindsEqual(i.kind, other.kind); + } + + /** + * Determines if two given kinds are equal at the {@linkplain #archKind(CiKind) architecture} level + * in the context of the {@linkplain C1XCompilation#compilation()} compilation. + */ + public static boolean archKindsEqual(CiKind k1, CiKind k2) { + C1XCompilation compilation = C1XCompilation.compilation(); + assert compilation != null : "missing compilation context"; + return compilation.archKindsEqual(k1, k2); + } + + /** + * Translates a given kind to a {@linkplain C1XCompilation#archKind(CiKind) canonical architecture} + * kind in the context of the {@linkplain C1XCompilation#compilation() current} compilation. + */ + public static CiKind archKind(CiKind kind) { + C1XCompilation compilation = C1XCompilation.compilation(); + assert compilation != null : "missing compilation context"; + return compilation.archKind(kind); + } + + + /** + * Checks that two instructions are equivalent, optionally comparing constants. + * @param x the first instruction + * @param y the second instruction + * @param compareConstants {@code true} if equivalent constants should be considered equivalent + * @return {@code true} if the instructions are equivalent; {@code false} otherwise + */ + public static boolean equivalent(Instruction x, Instruction y, boolean compareConstants) { + if (x == y) { + return true; + } + if (compareConstants && x != null && y != null) { + if (x.isConstant() && x.asConstant().equivalent(y.asConstant())) { + return true; + } + } + return false; + } + + /** + * Converts a given instruction to a value string. The representation of an instruction as + * a value is formed by concatenating the {@linkplain com.sun.cri.ci.CiKind#typeChar character} denoting its + * {@linkplain Value#kind kind} and its {@linkplain Value#id()}. For example, {@code "i13"}. + * + * @param value the instruction to convert to a value string. If {@code value == null}, then "-" is returned. + * @return the instruction representation as a string + */ + public static String valueString(Value value) { + return (value == null) ? "-" : ("" + value.kind.typeChar + value.id()); + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/value/FrameState.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/value/FrameState.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,516 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.value; + +import static com.oracle.max.graal.compiler.value.ValueUtil.*; + +import java.util.*; + +import com.oracle.max.graal.compiler.*; +import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.compiler.ir.*; +import com.oracle.max.graal.graph.*; +import com.sun.cri.ci.*; +import com.sun.cri.ri.*; + +/** + * The {@code FrameState} class encapsulates the frame state (i.e. local variables and + * operand stack) at a particular point in the abstract interpretation. + */ +public final class FrameState extends Value implements FrameStateAccess { + + private static final int INPUT_COUNT = 1; + + private static final int INPUT_OUTER_FRAME_STATE = 0; + + protected final int localsSize; + + protected final int stackSize; + + protected final int locksSize; + + private static final int SUCCESSOR_COUNT = 0; + + @Override + protected int inputCount() { + return super.inputCount() + localsSize + stackSize + locksSize; + } + + @Override + protected int successorCount() { + return super.successorCount() + SUCCESSOR_COUNT; + } + + public FrameState outerFrameState() { + return (FrameState) inputs().get(super.inputCount() + INPUT_OUTER_FRAME_STATE); + } + + public FrameState setOuterFrameState(FrameState n) { + return (FrameState) inputs().set(super.inputCount() + INPUT_OUTER_FRAME_STATE, n); + } + + @Override + public void setValueAt(int i, Value x) { + inputs().set(INPUT_COUNT + i, x); + } + + /** + * The bytecode index to which this frame state applies. This will be {@code -1} + * iff this state is mutable. + */ + public final int bci; + + public final RiMethod method; + + /** + * Creates a {@code FrameState} for the given scope and maximum number of stack and local variables. + * + * @param bci the bytecode index of the frame state + * @param localsSize number of locals + * @param stackSize size of the stack + * @param lockSize number of locks + */ + public FrameState(RiMethod method, int bci, int localsSize, int stackSize, int locksSize, Graph graph) { + super(CiKind.Illegal, localsSize + stackSize + locksSize + INPUT_COUNT, SUCCESSOR_COUNT, graph); + this.method = method; + this.bci = bci; + this.localsSize = localsSize; + this.stackSize = stackSize; + this.locksSize = locksSize; + C1XMetrics.FrameStatesCreated++; + C1XMetrics.FrameStateValuesCreated += localsSize + stackSize + locksSize; + } + + FrameState(RiMethod method, int bci, Value[] locals, Value[] stack, int stackSize, ArrayList locks, Graph graph) { + this(method, bci, locals.length, stackSize, locks.size(), graph); + for (int i = 0; i < locals.length; i++) { + setValueAt(i, locals[i]); + } + for (int i = 0; i < stackSize; i++) { + setValueAt(localsSize + i, stack[i]); + } + for (int i = 0; i < locks.size(); i++) { + setValueAt(locals.length + stackSize + i, locks.get(i)); + } + } + + /** + * Gets a copy of this frame state. + */ + public FrameState duplicate(int bci) { + FrameState other = copy(bci); + other.inputs().setAll(inputs()); + return other; + } + + /** + * Gets a copy of this frame state without the stack. + */ + @Override + public FrameState duplicateWithEmptyStack(int bci) { + FrameState other = new FrameState(method, bci, localsSize, 0, locksSize(), graph()); + for (int i = 0; i < localsSize; i++) { + other.setValueAt(i, localAt(i)); + } + for (int i = 0; i < locksSize; i++) { + other.setValueAt(localsSize + i, lockAt(i)); + } + other.setOuterFrameState(outerFrameState()); + return other; + } + + /** + * Creates a copy of this frame state with one stack element of type popKind popped from the stack and the + * values in pushedValues pushed on the stack. The pushedValues are expected to be in slot encoding: a long + * or double is followed by a null slot. + */ + public FrameState duplicateModified(int bci, CiKind popKind, Value... pushedValues) { + int popSlots = popKind.sizeInSlots(); + int pushSlots = pushedValues.length; + FrameState other = new FrameState(method, bci, localsSize, stackSize - popSlots + pushSlots, locksSize(), graph()); + for (int i = 0; i < localsSize; i++) { + other.setValueAt(i, localAt(i)); + } + for (int i = 0; i < stackSize - popSlots; i++) { + other.setValueAt(localsSize + i, stackAt(i)); + } + int slot = localsSize + stackSize - popSlots; + for (int i = 0; i < pushSlots; i++) { + other.setValueAt(slot++, pushedValues[i]); + } + for (int i = 0; i < locksSize; i++) { + other.setValueAt(localsSize + other.stackSize + i, lockAt(i)); + } + other.setOuterFrameState(outerFrameState()); + return other; + } + + public boolean isCompatibleWith(FrameStateAccess other) { + if (stackSize() != other.stackSize() || localsSize() != other.localsSize() || locksSize() != other.locksSize()) { + return false; + } + for (int i = 0; i < stackSize(); i++) { + Value x = stackAt(i); + Value y = other.stackAt(i); + if (x != y && typeMismatch(x, y)) { + return false; + } + } + for (int i = 0; i < locksSize(); i++) { + if (lockAt(i) != other.lockAt(i)) { + return false; + } + } + if (other.outerFrameState() != outerFrameState()) { + return false; + } + return true; + } + + /** + * Gets the size of the local variables. + */ + public int localsSize() { + return localsSize; + } + + /** + * Gets the current size (height) of the stack. + */ + public int stackSize() { + return stackSize; + } + + /** + * Gets number of locks held by this frame state. + */ + public int locksSize() { + return locksSize; + } + + /** + * Invalidates the local variable at the specified index. If the specified index refers to a doubleword local, then + * invalidates the high word as well. + * + * @param i the index of the local to invalidate + */ + public void invalidateLocal(int i) { + // note that for double word locals, the high slot should already be null + // unless the local is actually dead and the high slot is being reused; + // in either case, it is not necessary to null the high slot + setValueAt(i, null); + } + + /** + * Stores a given local variable at the specified index. If the value is a {@linkplain CiKind#isDoubleWord() double word}, + * then the next local variable index is also overwritten. + * + * @param i the index at which to store + * @param x the instruction which produces the value for the local + */ + public void storeLocal(int i, Value x) { + assert i < localsSize : "local variable index out of range: " + i; + invalidateLocal(i); + setValueAt(i, x); + if (isDoubleWord(x)) { + // (tw) if this was a double word then kill i+1 + setValueAt(i + 1, null); + } + if (i > 0) { + // if there was a double word at i - 1, then kill it + Value p = localAt(i - 1); + if (isDoubleWord(p)) { + setValueAt(i - 1, null); + } + } + } + + /** + * Gets the value in the local variables at the specified index. + * + * @param i the index into the locals + * @return the instruction that produced the value for the specified local + */ + public Value localAt(int i) { + assert i < localsSize : "local variable index out of range: " + i; + return valueAt(i); + } + + /** + * Get the value on the stack at the specified stack index. + * + * @param i the index into the stack, with {@code 0} being the bottom of the stack + * @return the instruction at the specified position in the stack + */ + public Value stackAt(int i) { + assert i >= 0 && i < (localsSize + stackSize); + return valueAt(localsSize + i); + } + + /** + * Retrieves the lock at the specified index in the lock stack. + * @param i the index into the lock stack + * @return the instruction which produced the object at the specified location in the lock stack + */ + public Value lockAt(int i) { + assert i >= 0; + return valueAt(localsSize + stackSize + i); + } + + /** + * Inserts a phi statement into the stack at the specified stack index. + * @param block the block begin for which we are creating the phi + * @param i the index into the stack for which to create a phi + */ + public Phi setupPhiForStack(Merge block, int i) { + Value p = stackAt(i); + if (p != null) { + if (p instanceof Phi) { + Phi phi = (Phi) p; + if (phi.block() == block) { + return phi; + } + } + Phi phi = new Phi(p.kind, block, graph()); + setValueAt(localsSize + i, phi); + return phi; + } + return null; + } + + /** + * Inserts a phi statement for the local at the specified index. + * @param block the block begin for which we are creating the phi + * @param i the index of the local variable for which to create the phi + */ + public Phi setupPhiForLocal(Merge block, int i) { + Value p = localAt(i); + if (p instanceof Phi) { + Phi phi = (Phi) p; + if (phi.block() == block) { + return phi; + } + } + Phi phi = new Phi(p.kind, block, graph()); + storeLocal(i, phi); + return phi; + } + + /** + * Gets the value at a specified index in the set of operand stack and local values represented by this frame. + * This method should only be used to iterate over all the values in this frame, irrespective of whether + * they are on the stack or in local variables. + * To iterate the stack slots, the {@link #stackAt(int)} and {@link #stackSize()} methods should be used. + * To iterate the local variables, the {@link #localAt(int)} and {@link #localsSize()} methods should be used. + * + * @param i a value in the range {@code [0 .. valuesSize()]} + * @return the value at index {@code i} which may be {@code null} + */ + public Value valueAt(int i) { + assert i < (localsSize + stackSize + locksSize); + return (Value) inputs().get(INPUT_COUNT + i); + } + + /** + * The number of operand stack slots and local variables in this frame. + * This method should typically only be used in conjunction with {@link #valueAt(int)}. + * To iterate the stack slots, the {@link #stackAt(int)} and {@link #stackSize()} methods should be used. + * To iterate the local variables, the {@link #localAt(int)} and {@link #localsSize()} methods should be used. + * + * @return the number of local variables in this frame + */ + public int valuesSize() { + return localsSize + stackSize; + } + + private void checkSize(FrameStateAccess other) { + if (other.stackSize() != stackSize()) { + throw new CiBailout("stack sizes do not match"); + } else if (other.localsSize() != localsSize) { + throw new CiBailout("local sizes do not match"); + } + } + + public void merge(Merge block, FrameStateAccess other) { + checkSize(other); + for (int i = 0; i < valuesSize(); i++) { + Value x = valueAt(i); + if (x != null) { + Value y = other.valueAt(i); + if (x != y || ((x instanceof Phi) && ((Phi) x).block() == block)) { + if (typeMismatch(x, y)) { + if (x instanceof Phi) { + Phi phi = (Phi) x; + if (phi.block() == block) { + phi.makeDead(); + } + } + setValueAt(i, null); + continue; + } + Phi phi = null; + if (i < localsSize) { + // this a local + phi = setupPhiForLocal(block, i); + } else { + // this is a stack slot + phi = setupPhiForStack(block, i - localsSize); + } + + Phi originalPhi = phi; + if (phi.valueCount() == 0) { + int size = block.predecessors().size(); + for (int j = 0; j < size; ++j) { + phi = phi.addInput(x); + } + phi = phi.addInput((x == y) ? phi : y); + } else { + phi = phi.addInput((x == y) ? phi : y); + } + if (originalPhi != phi) { + for (int j = 0; j < other.localsSize() + other.stackSize(); ++j) { + if (other.valueAt(j) == originalPhi) { + other.setValueAt(j, phi); + } + } + } + + if (block instanceof LoopBegin) { +// assert phi.valueCount() == ((LoopBegin) block).loopEnd().predecessors().size() + 1 : "loop, valueCount=" + phi.valueCount() + " predSize= " + ((LoopBegin) block).loopEnd().predecessors().size(); + } else { + assert phi.valueCount() == block.predecessors().size() + 1 : "valueCount=" + phi.valueCount() + " predSize= " + block.predecessors().size(); + } + } + } + } + } + + public Merge block() { + for (Node usage : usages()) { + if (usage instanceof Merge) { + return (Merge) usage; + } + } + return null; + } + + /** + * The interface implemented by a client of {@link FrameState#forEachPhi(Merge, PhiProcedure)} and + * {@link FrameState#forEachLivePhi(Merge, PhiProcedure)}. + */ + public static interface PhiProcedure { + boolean doPhi(Phi phi); + } + + /** + * Checks whether this frame state has any {@linkplain Phi phi} statements. + */ + public boolean hasPhis() { + for (int i = 0; i < valuesSize(); i++) { + Value value = valueAt(i); + if (value instanceof Phi) { + return true; + } + } + return false; + } + + /** + * The interface implemented by a client of {@link FrameState#forEachLiveStateValue(ValueProcedure)}. + */ + public static interface ValueProcedure { + void doValue(Value value); + } + + /** + * Traverses all {@linkplain Value#isLive() live values} of this frame state. + * + * @param proc the call back called to process each live value traversed + */ + public void forEachLiveStateValue(ValueProcedure proc) { + for (int i = 0; i < valuesSize(); i++) { + Value value = valueAt(i); + if (value != null) { + proc.doValue(value); + } + } + if (outerFrameState() != null) { + outerFrameState().forEachLiveStateValue(proc); + } + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + String nl = String.format("%n"); + sb.append("[bci: ").append(bci).append("]").append(nl); + for (int i = 0; i < localsSize(); ++i) { + Value value = localAt(i); + sb.append(String.format(" local[%d] = %-8s : %s%n", i, value == null ? "bogus" : value.kind.javaName, value)); + } + for (int i = 0; i < stackSize(); ++i) { + Value value = stackAt(i); + sb.append(String.format(" stack[%d] = %-8s : %s%n", i, value == null ? "bogus" : value.kind.javaName, value)); + } + for (int i = 0; i < locksSize(); ++i) { + Value value = lockAt(i); + sb.append(String.format(" lock[%d] = %-8s : %s%n", i, value == null ? "bogus" : value.kind.javaName, value)); + } + return sb.toString(); + } + + @Override + public void accept(ValueVisitor v) { + v.visitFrameState(this); + } + + @Override + public void print(LogStream out) { + out.print("FrameState"); + } + + @Override + public FrameState copy() { + return new FrameState(method, bci, localsSize, stackSize, locksSize, graph()); + } + + + private FrameState copy(int newBci) { + return new FrameState(method, newBci, localsSize, stackSize, locksSize, graph()); + } + + @Override + public String shortName() { + return "FrameState@" + bci; + } + + public void visitFrameState(FrameState i) { + // nothing to do for now + } + + @Override + public Node copy(Graph into) { + FrameState x = new FrameState(method, bci, localsSize, stackSize, locksSize, into); + return x; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/value/FrameStateAccess.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/value/FrameStateAccess.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.value; + +import com.oracle.max.graal.compiler.ir.*; + +public interface FrameStateAccess { + + FrameState duplicate(int newBci); + + int localsSize(); + + int stackSize(); + + int locksSize(); + + Value valueAt(int i); + + Value localAt(int i); + + Value lockAt(int i); + + Value stackAt(int i); + + FrameState duplicateWithEmptyStack(int bci); + + void setValueAt(int j, Value v); + + Value outerFrameState(); + +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/value/FrameStateBuilder.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/value/FrameStateBuilder.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,507 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.value; + +import static com.oracle.max.graal.compiler.value.ValueUtil.*; +import static java.lang.reflect.Modifier.*; + +import java.util.*; + +import com.oracle.max.graal.compiler.ir.*; +import com.oracle.max.graal.graph.*; +import com.sun.cri.ci.*; +import com.sun.cri.ri.*; + + +public class FrameStateBuilder implements FrameStateAccess { + + private final Graph graph; + + private final Value[] locals; + private final Value[] stack; + private final ArrayList locks; + + private int stackIndex; + + private final RiMethod method; + + public FrameStateBuilder(RiMethod method, Graph graph) { + this.method = method; + this.graph = graph; + this.locals = new Value[method.maxLocals()]; + // we always need at least one stack slot (for exceptions) + int stackSize = Math.max(1, method.maxStackSize()); + this.stack = new Value[stackSize]; + + int javaIndex = 0; + int index = 0; + if (!isStatic(method.accessFlags())) { + // add the receiver and assume it is non null + Local local = new Local(method.holder().kind(), javaIndex, graph); + local.inputs().set(0, graph.start()); + local.setDeclaredType(method.holder()); + storeLocal(javaIndex, local); + javaIndex = 1; + index = 1; + } + RiSignature sig = method.signature(); + int max = sig.argumentCount(false); + RiType accessingClass = method.holder(); + for (int i = 0; i < max; i++) { + RiType type = sig.argumentTypeAt(i, accessingClass); + CiKind kind = type.kind().stackKind(); + Local local = new Local(kind, index, graph); + local.inputs().set(0, graph.start()); + if (type.isResolved()) { + local.setDeclaredType(type); + } + storeLocal(javaIndex, local); + javaIndex += kind.sizeInSlots(); + index++; + } + this.locks = new ArrayList(); + } + + public void initializeFrom(FrameState other) { + assert locals.length == other.localsSize() : "expected: " + locals.length + ", actual: " + other.localsSize(); + assert stack.length >= other.stackSize() : "expected: <=" + stack.length + ", actual: " + other.stackSize(); + + this.stackIndex = other.stackSize(); + for (int i = 0; i < other.localsSize(); i++) { + locals[i] = other.localAt(i); + } + for (int i = 0; i < other.stackSize(); i++) { + stack[i] = other.stackAt(i); + } + locks.clear(); + for (int i = 0; i < other.locksSize(); i++) { + locks.add(other.lockAt(i)); + } + } + + public FrameState create(int bci) { + return new FrameState(method, bci, locals, stack, stackIndex, locks, graph); + } + + @Override + public FrameState duplicateWithEmptyStack(int bci) { + FrameState frameState = new FrameState(method, bci, locals, new Value[0], 0, locks, graph); + frameState.setOuterFrameState(outerFrameState()); + return frameState; + } + + /** + * Pushes an instruction onto the stack with the expected type. + * @param kind the type expected for this instruction + * @param x the instruction to push onto the stack + */ + public void push(CiKind kind, Value x) { + assert kind != CiKind.Void; + xpush(assertKind(kind, x)); + if (kind.sizeInSlots() == 2) { + xpush(null); + } + } + + /** + * Pushes a value onto the stack without checking the type. + * @param x the instruction to push onto the stack + */ + public void xpush(Value x) { + assert x == null || !x.isDeleted(); + stack[stackIndex++] = x; + } + + /** + * Pushes a value onto the stack and checks that it is an int. + * @param x the instruction to push onto the stack + */ + public void ipush(Value x) { + xpush(assertInt(x)); + } + + /** + * Pushes a value onto the stack and checks that it is a float. + * @param x the instruction to push onto the stack + */ + public void fpush(Value x) { + xpush(assertFloat(x)); + } + + /** + * Pushes a value onto the stack and checks that it is an object. + * @param x the instruction to push onto the stack + */ + public void apush(Value x) { + xpush(assertObject(x)); + } + + /** + * Pushes a value onto the stack and checks that it is a word. + * @param x the instruction to push onto the stack + */ + public void wpush(Value x) { + xpush(assertWord(x)); + } + + /** + * Pushes a value onto the stack and checks that it is a JSR return address. + * @param x the instruction to push onto the stack + */ + public void jpush(Value x) { + xpush(assertJsr(x)); + } + + /** + * Pushes a value onto the stack and checks that it is a long. + * + * @param x the instruction to push onto the stack + */ + public void lpush(Value x) { + xpush(assertLong(x)); + xpush(null); + } + + /** + * Pushes a value onto the stack and checks that it is a double. + * @param x the instruction to push onto the stack + */ + public void dpush(Value x) { + xpush(assertDouble(x)); + xpush(null); + } + + public void pushReturn(CiKind kind, Value x) { + if (kind != CiKind.Void) { + push(kind.stackKind(), x); + } + } + + /** + * Pops an instruction off the stack with the expected type. + * @param kind the expected type + * @return the instruction on the top of the stack + */ + public Value pop(CiKind kind) { + assert kind != CiKind.Void; + if (kind.sizeInSlots() == 2) { + xpop(); + } + return assertKind(kind, xpop()); + } + + /** + * Pops a value off of the stack without checking the type. + * @return x the instruction popped off the stack + */ + public Value xpop() { + Value result = stack[--stackIndex]; + assert result == null || !result.isDeleted(); + return result; + } + + /** + * Pops a value off of the stack and checks that it is an int. + * @return x the instruction popped off the stack + */ + public Value ipop() { + return assertInt(xpop()); + } + + /** + * Pops a value off of the stack and checks that it is a float. + * @return x the instruction popped off the stack + */ + public Value fpop() { + return assertFloat(xpop()); + } + + /** + * Pops a value off of the stack and checks that it is an object. + * @return x the instruction popped off the stack + */ + public Value apop() { + return assertObject(xpop()); + } + + /** + * Pops a value off of the stack and checks that it is a word. + * @return x the instruction popped off the stack + */ + public Value wpop() { + return assertWord(xpop()); + } + + /** + * Pops a value off of the stack and checks that it is a JSR return address. + * @return x the instruction popped off the stack + */ + public Value jpop() { + return assertJsr(xpop()); + } + + /** + * Pops a value off of the stack and checks that it is a long. + * @return x the instruction popped off the stack + */ + public Value lpop() { + assertHigh(xpop()); + return assertLong(xpop()); + } + + /** + * Pops a value off of the stack and checks that it is a double. + * @return x the instruction popped off the stack + */ + public Value dpop() { + assertHigh(xpop()); + return assertDouble(xpop()); + } + + /** + * Pop the specified number of slots off of this stack and return them as an array of instructions. + * @param size the number of arguments off of the stack + * @return an array containing the arguments off of the stack + */ + public Value[] popArguments(int size) { + int base = stackIndex - size; + Value[] r = new Value[size]; + for (int i = 0; i < size; ++i) { + assert stack[base + i] != null || stack[base + i - 1].kind.jvmSlots == 2; + r[i] = stack[base + i]; + } + stackIndex = base; + return r; + } + + public CiKind peekKind() { + Value top = stackAt(stackSize() - 1); + if (top == null) { + top = stackAt(stackSize() - 2); + assert top != null; + assert top.kind.isDoubleWord(); + } + return top.kind; + } + + /** + * Truncates this stack to the specified size. + * @param size the size to truncate to + */ + public void truncateStack(int size) { + stackIndex = size; + assert stackIndex >= 0; + } + + /** + * Clears all values on this stack. + */ + public void clearStack() { + stackIndex = 0; + } + + /** + * Loads the local variable at the specified index. + * + * @param i the index of the local variable to load + * @return the instruction that produced the specified local + */ + public Value loadLocal(int i) { + Value x = locals[i]; + if (x != null) { + if (x instanceof Phi && ((Phi) x).isDead()) { + return null; + } + assert x.kind.isSingleWord() || locals[i + 1] == null || locals[i + 1] instanceof Phi; + } + return x; + } + + /** + * Stores a given local variable at the specified index. If the value is a {@linkplain CiKind#isDoubleWord() double word}, + * then the next local variable index is also overwritten. + * + * @param i the index at which to store + * @param x the instruction which produces the value for the local + */ + public void storeLocal(int i, Value x) { + locals[i] = x; + if (isDoubleWord(x)) { + // (tw) if this was a double word then kill i+1 + locals[i + 1] = null; + } + if (i > 0) { + // if there was a double word at i - 1, then kill it + Value p = locals[i - 1]; + if (isDoubleWord(p)) { + locals[i - 1] = null; + } + } + } + + /** + * Locks a new object within the specified IRScope. + * @param scope the IRScope in which this locking operation occurs + * @param obj the object being locked + */ + public void lock(Value obj) { + locks.add(obj); + } + + /** + * Unlock the lock on the top of the stack. + */ + public void unlock() { + locks.remove(locks.size() - 1); + } + + /** + * Get the value on the stack at the specified stack index. + * + * @param i the index into the stack, with {@code 0} being the bottom of the stack + * @return the instruction at the specified position in the stack + */ + public final Value stackAt(int i) { + return stack[i]; + } + + /** + * Gets the value in the local variables at the specified index. + * + * @param i the index into the locals + * @return the instruction that produced the value for the specified local + */ + public final Value localAt(int i) { + return locals[i]; + } + + /** + * Retrieves the lock at the specified index in the lock stack. + * @param i the index into the lock stack + * @return the instruction which produced the object at the specified location in the lock stack + */ + public final Value lockAt(int i) { + return locks.get(i); + } + + /** + * Returns the size of the local variables. + * + * @return the size of the local variables + */ + public int localsSize() { + return locals.length; + } + + /** + * Gets number of locks held by this frame state. + */ + public int locksSize() { + return locks.size(); + } + + /** + * Gets the current size (height) of the stack. + */ + public int stackSize() { + return stackIndex; + } + + public Iterator locals() { + return new ValueArrayIterator(locals); + } + + public Iterator stack() { + return new ValueArrayIterator(locals); + } + + public List locks() { + return Collections.unmodifiableList(locks); + } + + + private static class ValueArrayIterator implements Iterator { + private final Value[] array; + private int index; + private int length; + + public ValueArrayIterator(Value[] array, int length) { + assert length <= array.length; + this.array = array; + this.index = 0; + } + + public ValueArrayIterator(Value[] array) { + this(array, array.length); + } + + @Override + public boolean hasNext() { + return index < array.length; + } + + @Override + public Value next() { + return array[index++]; + } + + @Override + public void remove() { + throw new UnsupportedOperationException("cannot remove from array"); + } + + } + + + @Override + public FrameState duplicate(int bci) { + return create(bci); + } + + @Override + public Value valueAt(int i) { + if (i < locals.length) { + return locals[i]; + } else if (i < locals.length + stackIndex) { + return stack[i - locals.length]; + } else { + return locks.get(i - locals.length - stack.length); + } + } + + @Override + public void setValueAt(int i, Value v) { + if (i < locals.length) { + locals[i] = v; + } else if (i < locals.length + stackIndex) { + stack[i - locals.length] = v; + } else { + locks.set(i - locals.length - stack.length, v); + } + } + + @Override + public FrameState outerFrameState() { + return null; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/value/ValueUtil.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/value/ValueUtil.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.compiler.value; + +import com.oracle.max.graal.compiler.ir.*; +import com.oracle.max.graal.compiler.util.*; +import com.sun.cri.ci.*; + + +public class ValueUtil { + + public static Value assertKind(CiKind kind, Value x) { + assert x != null && (x.kind == kind) : "kind=" + kind + ", value=" + x + ((x == null) ? "" : ", value.kind=" + x.kind); + return x; + } + + public static Value assertLong(Value x) { + assert x != null && (x.kind == CiKind.Long); + return x; + } + + public static Value assertJsr(Value x) { + assert x != null && (x.kind == CiKind.Jsr); + return x; + } + + public static Value assertInt(Value x) { + assert x != null && (x.kind == CiKind.Int); + return x; + } + + public static Value assertFloat(Value x) { + assert x != null && (x.kind == CiKind.Float); + return x; + } + + public static Value assertObject(Value x) { + assert x != null && (x.kind == CiKind.Object); + return x; + } + + public static Value assertWord(Value x) { + assert x != null && (x.kind == CiKind.Word); + return x; + } + + public static Value assertDouble(Value x) { + assert x != null && (x.kind == CiKind.Double); + return x; + } + + public static void assertHigh(Value x) { + assert x == null; + } + + public static boolean typeMismatch(Value x, Value y) { + return y == null || !Util.archKindsEqual(x, y); + } + + public static boolean isDoubleWord(Value x) { + return x != null && x.kind.isDoubleWord(); + } + +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/value/package-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/value/package-info.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2010, 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @author Ben Titzer + */ +package com.oracle.max.graal.compiler.value; diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/opt/CanonicalizerPhase.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/opt/CanonicalizerPhase.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.max.graal.opt; - -import java.util.*; - -import com.oracle.graal.graph.*; -import com.sun.c1x.*; - -public class CanonicalizerPhase extends Phase { - - - @Override - protected void run(Graph graph) { - NodeBitMap visited = graph.createNodeBitMap(); - List nodes = new ArrayList(graph.getNodes()); - for (Node n : nodes) { - if (n == null) { - continue; - } - if (!visited.isMarked(n)) { - this.canonicalize(n, visited); - } - } - } - - private void canonicalize(Node n, NodeBitMap visited) { - visited.mark(n); - for (Node input : n.inputs()) { - if (input == null) { - continue; - } - if (!visited.isNew(input) && !visited.isMarked(input)) { - canonicalize(input, visited); - } - } - - CanonicalizerOp op = n.lookup(CanonicalizerOp.class); - if (op != null) { - Node canonical = op.canonical(n); - if (canonical != n) { - n.replace(canonical); - C1XMetrics.NodesCanonicalized++; - } - } - } - - public interface CanonicalizerOp extends Op { - Node canonical(Node node); - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/schedule/Block.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/schedule/Block.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,132 +0,0 @@ -/* - * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.max.graal.schedule; - -import java.util.*; - -import com.oracle.graal.graph.*; -import com.sun.c1x.ir.*; - - -public class Block { - - private int blockID; - private final List successors = new ArrayList(); - private final List predecessors = new ArrayList(); - private List instructions = new ArrayList(); - private Block dominator; - private final List dominators = new ArrayList(); - - private Node firstNode; - private Node lastNode; - - public Node firstNode() { - return firstNode; - } - - public void setFirstNode(Node node) { - this.firstNode = node; - } - - public Node lastNode() { - return lastNode; - } - - public void setLastNode(Node node) { - this.lastNode = node; - } - - public List getSuccessors() { - return Collections.unmodifiableList(successors); - } - - public void setDominator(Block dominator) { - assert this.dominator == null; - assert dominator != null; - this.dominator = dominator; - dominator.dominators.add(this); - } - - public List getDominators() { - return Collections.unmodifiableList(dominators); - } - - public List getInstructions() { - return instructions; - } - - public List getPredecessors() { - return Collections.unmodifiableList(predecessors); - } - - public Block(int blockID) { - this.blockID = blockID; - } - - public void addSuccessor(Block other) { - successors.add(other); - other.predecessors.add(this); - } - - public int blockID() { - return blockID; - } - - /** - * Iterate over this block, its exception handlers, and its successors, in that order. - * - * @param closure the closure to apply to each block - */ - public void iteratePreOrder(BlockClosure closure) { - // XXX: identity hash map might be too slow, consider a boolean array or a mark field - iterate(new IdentityHashMap(), closure); - } - - private void iterate(IdentityHashMap mark, BlockClosure closure) { - if (!mark.containsKey(this)) { - mark.put(this, this); - closure.apply(this); - - iterateReverse(mark, closure, this.successors); - } - } - - private void iterateReverse(IdentityHashMap mark, BlockClosure closure, List list) { - for (int i = list.size() - 1; i >= 0; i--) { - list.get(i).iterate(mark, closure); - } - } - - @Override - public String toString() { - return "B" + blockID; - } - - public Block dominator() { - return dominator; - } - - public void setInstructions(List instructions) { - this.instructions = instructions; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/schedule/Schedule.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/schedule/Schedule.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,463 +0,0 @@ -/* - * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.max.graal.schedule; - -import java.util.*; - -import com.oracle.graal.graph.*; -import com.sun.c1x.debug.*; -import com.sun.c1x.ir.*; -import com.sun.c1x.value.*; -import com.sun.cri.ci.*; - - -public class Schedule { - private final List blocks = new ArrayList(); - private final NodeMap nodeToBlock; - private final Graph graph; - - public Schedule(Graph graph) { - this.graph = graph; - nodeToBlock = graph.createNodeMap(); - identifyBlocks(); - } - public List getBlocks() { - return Collections.unmodifiableList(blocks); - } - - public NodeMap getNodeToBlock() { - return nodeToBlock; - } - - private Block createBlock() { - Block b = new Block(blocks.size()); - blocks.add(b); - return b; - } - - private Block assignBlock(Node n) { - Block curBlock = nodeToBlock.get(n); - if (curBlock == null) { - curBlock = createBlock(); - return assignBlock(n, curBlock); - } - return curBlock; - } - - - private Block assignBlock(Node n, Block b) { - assert nodeToBlock.get(n) == null; - nodeToBlock.set(n, b); - if (b.firstNode() == null) { - b.setFirstNode(n); - b.setLastNode(n); - } else { - if (b.lastNode() != null) { - b.getInstructions().add(b.lastNode()); - } - b.setLastNode(n); - } - b.setLastNode(n); - return b; - } - - public static boolean isFixed(Node n) { - return n != null && ((n instanceof FixedNode) || n == n.graph().start()); - } - - public static boolean isBlockEnd(Node n) { - return trueSuccessorCount(n) > 1 || n instanceof Anchor || n instanceof Return || n instanceof Unwind; - } - - private void identifyBlocks() { - // Identify blocks. - final ArrayList blockBeginNodes = new ArrayList(); - NodeIterator.iterate(EdgeType.SUCCESSORS, graph.start(), null, new NodeVisitor() { - @Override - public boolean visit(Node n) { - if (!isFixed(n)) { - return false; - } - - if (n instanceof LoopBegin) { - // a LoopBegin is always a merge - assignBlock(n); - blockBeginNodes.add(n); - return true; - } - - Node singlePred = null; - for (Node pred : n.predecessors()) { - if (isFixed(pred)) { - if (singlePred == null) { - singlePred = pred; - } else { - // We have more than one predecessor => we are a merge block. - assignBlock(n); - blockBeginNodes.add(n); - return true; - } - } - } - - if (singlePred == null) { - // We have no predecessor => we are the start block. - assignBlock(n); - blockBeginNodes.add(n); - } else { - // We have a single predecessor => check its successor count. - if (isBlockEnd(singlePred)) { - Block b = assignBlock(n); - blockBeginNodes.add(n); - } else { - assignBlock(n, nodeToBlock.get(singlePred)); - } - } - return true; - }} - ); - - // Connect blocks. - for (Node n : blockBeginNodes) { - Block block = nodeToBlock.get(n); - for (Node pred : n.predecessors()) { - if (isFixed(pred)) { - Block predBlock = nodeToBlock.get(pred); - predBlock.addSuccessor(block); - } - } - - if (n instanceof Merge) { - for (Node usage : n.usages()) { - if (usage instanceof Phi) { - nodeToBlock.set(usage, block); - } - } - } - } - - for (Node n : graph.getNodes()) { - if (n instanceof FrameState) { - FrameState f = (FrameState) n; - if (f.predecessors().size() == 1) { - Block predBlock = nodeToBlock.get(f.predecessors().get(0)); - assert predBlock != null; - nodeToBlock.set(f, predBlock); - predBlock.getInstructions().add(f); - } else { - assert f.predecessors().size() == 0; - } - } - } - - computeDominators(); - - - - // Add successors of loop end nodes. Makes the graph cyclic. - for (Node n : blockBeginNodes) { - Block block = nodeToBlock.get(n); - if (n instanceof LoopBegin) { - LoopBegin loopBegin = (LoopBegin) n; - nodeToBlock.get(loopBegin.loopEnd()).addSuccessor(block); - } - } - - assignLatestPossibleBlockToNodes(); - sortNodesWithinBlocks(); - - //print(); - } - - private void assignLatestPossibleBlockToNodes() { - for (Node n : graph.getNodes()) { - assignLatestPossibleBlockToNode(n); - } - } - - private Block assignLatestPossibleBlockToNode(Node n) { - if (n == null) { - return null; - } - - Block prevBlock = nodeToBlock.get(n); - if (prevBlock != null) { - return prevBlock; - } - - Block block = null; - for (Node succ : n.successors()) { - block = getCommonDominator(block, assignLatestPossibleBlockToNode(succ)); - } - for (Node usage : n.usages()) { - if (usage instanceof Phi) { - Phi phi = (Phi) usage; - Merge merge = phi.block(); - Block mergeBlock = nodeToBlock.get(merge); - assert mergeBlock != null; - for (int i = 0; i < phi.valueCount(); ++i) { - if (phi.valueAt(i) == n) { - if (mergeBlock.getPredecessors().size() == 0) { - TTY.println(merge.toString()); - TTY.println(phi.toString()); - TTY.println(merge.predecessors().toString()); - TTY.println("value count: " + phi.valueCount()); - } - block = getCommonDominator(block, mergeBlock.getPredecessors().get(i)); - } - } - } else if (usage instanceof FrameState && ((FrameState) usage).block() != null) { - Merge merge = ((FrameState) usage).block(); - for (Node pred : merge.predecessors()) { - if (isFixed(pred)) { - block = getCommonDominator(block, nodeToBlock.get(pred)); - } - } - } else { - block = getCommonDominator(block, assignLatestPossibleBlockToNode(usage)); - } - } - - nodeToBlock.set(n, block); - if (block != null) { - block.getInstructions().add(n); - } - return block; - } - - private Block getCommonDominator(Block a, Block b) { - if (a == null) { - return b; - } - if (b == null) { - return a; - } - return commonDominator(a, b); - } - - private void sortNodesWithinBlocks() { - NodeBitMap map = graph.createNodeBitMap(); - for (Block b : blocks) { - sortNodesWithinBlocks(b, map); - } - } - - private void sortNodesWithinBlocks(Block b, NodeBitMap map) { - List instructions = b.getInstructions(); - List sortedInstructions = new ArrayList(); - assert !map.isMarked(b.firstNode()) && nodeToBlock.get(b.firstNode()) == b; - - boolean scheduleFirst = true; - - if (b.firstNode() == b.lastNode()) { - Node node = b.firstNode(); - if (!(node instanceof Merge)) { - scheduleFirst = false; - } - } - if (scheduleFirst) { - addToSorting(b, b.firstNode(), sortedInstructions, map); - } - for (Node i : instructions) { - addToSorting(b, i, sortedInstructions, map); - } - addToSorting(b, b.lastNode(), sortedInstructions, map); - //assert b.firstNode() == sortedInstructions.get(0) : b.firstNode(); - // assert b.lastNode() == sortedInstructions.get(sortedInstructions.size() - 1); - b.setInstructions(sortedInstructions); -// TTY.println("Block " + b); -// for (Node n : sortedInstructions) { -// TTY.println("Node: " + n); -// } - } - - private void addToSorting(Block b, Node i, List sortedInstructions, NodeBitMap map) { - if (i == null || map.isMarked(i) || nodeToBlock.get(i) != b || i instanceof Phi || i instanceof Local) { - return; - } - - for (Node input : i.inputs()) { - addToSorting(b, input, sortedInstructions, map); - } - - for (Node pred : i.predecessors()) { - addToSorting(b, pred, sortedInstructions, map); - } - - map.mark(i); - - for (Node succ : i.successors()) { - if (succ instanceof FrameState) { - addToSorting(b, succ, sortedInstructions, map); - } - } - - // Now predecessors and inputs are scheduled => we can add this node. - if (!(i instanceof FrameState)) { - sortedInstructions.add(i); - } - } - - private void computeDominators() { - Block dominatorRoot = nodeToBlock.get(graph.start()); - assert dominatorRoot.getPredecessors().size() == 0; - CiBitMap visited = new CiBitMap(blocks.size()); - visited.set(dominatorRoot.blockID()); - LinkedList workList = new LinkedList(); - workList.add(dominatorRoot); - - while (!workList.isEmpty()) { - Block b = workList.remove(); - - List predecessors = b.getPredecessors(); - if (predecessors.size() == 1) { - b.setDominator(predecessors.get(0)); - } else if (predecessors.size() > 0) { - boolean delay = false; - for (Block pred : predecessors) { - if (pred != dominatorRoot && pred.dominator() == null) { - delay = true; - break; - } - } - - if (delay) { - workList.add(b); - continue; - } - - Block dominator = null; - for (Block pred : predecessors) { - if (dominator == null) { - dominator = pred; - } else { - dominator = commonDominator(dominator, pred); - } - } - b.setDominator(dominator); - } - - for (Block succ : b.getSuccessors()) { - if (!visited.get(succ.blockID())) { - visited.set(succ.blockID()); - workList.add(succ); - } - } - } - } - - public Block commonDominator(Block a, Block b) { - CiBitMap bitMap = new CiBitMap(blocks.size()); - Block cur = a; - while (cur != null) { - bitMap.set(cur.blockID()); - cur = cur.dominator(); - } - - cur = b; - while (cur != null) { - if (bitMap.get(cur.blockID())) { - return cur; - } - cur = cur.dominator(); - } - - print(); - assert false : "no common dominator between " + a + " and " + b; - return null; - } - - private void print() { - TTY.println("============================================"); - TTY.println("%d blocks", blocks.size()); - - for (Block b : blocks) { - TTY.println(); - TTY.print(b.toString()); - - TTY.print(" succs="); - for (Block succ : b.getSuccessors()) { - TTY.print(succ + ";"); - } - - TTY.print(" preds="); - for (Block pred : b.getPredecessors()) { - TTY.print(pred + ";"); - } - - if (b.dominator() != null) { - TTY.print(" dom=" + b.dominator()); - } - TTY.println(); - - if (b.getInstructions().size() > 0) { - TTY.print("first instr: " + b.getInstructions().get(0)); - TTY.print("last instr: " + b.getInstructions().get(b.getInstructions().size() - 1)); - } - } - -/* - TTY.println("============================================"); - TTY.println("%d nodes", nodeToBlock.size()); - for (Node n : graph.getNodes()) { - if (n != null) { - TTY.print("Node %d: %s", n.id(), n.getClass().toString()); - Block curBlock = nodeToBlock.get(n); - if (curBlock != null) { - TTY.print(" %s", curBlock); - } - TTY.println(); - } - }*/ - } - - public static int trueSuccessorCount(Node n) { - if (n == null) { - return 0; - } - int i = 0; - for (Node s : n.successors()) { - if (isFixed(s)) { - i++; - } - } - return i; - } - - public static int truePredecessorCount(Node n) { - if (n == null) { - return 0; - } - int i = 0; - for (Node s : n.predecessors()) { - if (isFixed(s)) { - i++; - } - } - - if (n instanceof LoopBegin) { - i++; - } - return i; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/C1XCompilation.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/C1XCompilation.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,310 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.c1x; - -import java.util.*; - -import com.oracle.max.asm.*; -import com.sun.c1x.alloc.*; -import com.sun.c1x.asm.*; -import com.sun.c1x.debug.*; -import com.sun.c1x.gen.*; -import com.sun.c1x.gen.LIRGenerator.*; -import com.sun.c1x.graph.*; -import com.sun.c1x.lir.*; -import com.sun.c1x.observer.*; -import com.sun.c1x.value.*; -import com.sun.cri.ci.*; -import com.sun.cri.ri.*; - -/** - * This class encapsulates global information about the compilation of a particular method, - * including a reference to the runtime, statistics about the compiled code, etc. - */ -public final class C1XCompilation { - - private static ThreadLocal currentCompilation = new ThreadLocal(); - - public final C1XCompiler compiler; - public final CiTarget target; - public final RiRuntime runtime; - public final RiMethod method; - public final RiRegisterConfig registerConfig; - public final CiStatistics stats; - public final CiAssumptions assumptions = new CiAssumptions(); - public final FrameState placeholderState; - - public CompilerGraph graph = new CompilerGraph(); - - private boolean hasExceptionHandlers; - private final C1XCompilation parent; - - /** - * @see #setNotTypesafe() - * @see #isTypesafe() - */ - private boolean typesafe = true; - - private int nextID = 1; - - private FrameMap frameMap; - private TargetMethodAssembler assembler; - - private IR hir; - - private LIRGenerator lirGenerator; - - /** - * Creates a new compilation for the specified method and runtime. - * - * @param compiler the compiler - * @param method the method to be compiled or {@code null} if generating code for a stub - * @param osrBCI the bytecode index for on-stack replacement, if requested - * @param stats externally supplied statistics object to be used if not {@code null} - */ - public C1XCompilation(C1XCompiler compiler, RiMethod method, int osrBCI, CiStatistics stats) { - if (osrBCI != -1) { - throw new CiBailout("No OSR supported"); - } - this.parent = currentCompilation.get(); - currentCompilation.set(this); - this.compiler = compiler; - this.target = compiler.target; - this.runtime = compiler.runtime; - this.method = method; - this.stats = stats == null ? new CiStatistics() : stats; - this.registerConfig = method == null ? compiler.globalStubRegisterConfig : runtime.getRegisterConfig(method); - this.placeholderState = method != null && method.minimalDebugInfo() ? new FrameState(method, 0, 0, 0, 0, graph) : null; - - if (compiler.isObserved()) { - compiler.fireCompilationStarted(new CompilationEvent(this)); - } - } - - public void close() { - currentCompilation.set(parent); - } - - public IR hir() { - return hir; - } - - /** - * Records that this compilation has exception handlers. - */ - public void setHasExceptionHandlers() { - hasExceptionHandlers = true; - } - - /** - * Translates a given kind to a canonical architecture kind. - * This is an identity function for all but {@link CiKind#Word} - * which is translated to {@link CiKind#Int} or {@link CiKind#Long} - * depending on whether or not this is a {@linkplain #is64Bit() 64-bit} - * compilation. - */ - public CiKind archKind(CiKind kind) { - if (kind.isWord()) { - return target.arch.is64bit() ? CiKind.Long : CiKind.Int; - } - return kind; - } - - /** - * Determines if two given kinds are equal at the {@linkplain #archKind(CiKind) architecture} level. - */ - public boolean archKindsEqual(CiKind kind1, CiKind kind2) { - return archKind(kind1) == archKind(kind2); - } - - /** - * Records an assumption that the specified type has no finalizable subclasses. - * - * @param receiverType the type that is assumed to have no finalizable subclasses - * @return {@code true} if the assumption was recorded and can be assumed; {@code false} otherwise - */ - public boolean recordNoFinalizableSubclassAssumption(RiType receiverType) { - return false; - } - - /** - * Converts this compilation to a string. - * - * @return a string representation of this compilation - */ - @Override - public String toString() { - return "compile: " + method; - } - - /** - * Builds the block map for the specified method. - * - * @param method the method for which to build the block map - * @param osrBCI the OSR bytecode index; {@code -1} if this is not an OSR - * @return the block map for the specified method - */ - public BlockMap getBlockMap(RiMethod method) { - BlockMap map = new BlockMap(method); - map.build(); - if (compiler.isObserved()) { - String label = CiUtil.format("BlockListBuilder %f %r %H.%n(%p)", method, true); - compiler.fireCompilationEvent(new CompilationEvent(this, label, map, method.code().length)); - } - stats.bytecodeCount += method.code().length; - return map; - } - - /** - * Returns the frame map of this compilation. - * @return the frame map - */ - public FrameMap frameMap() { - return frameMap; - } - - public TargetMethodAssembler assembler() { - if (assembler == null) { - AbstractAssembler asm = compiler.backend.newAssembler(registerConfig); - assembler = new TargetMethodAssembler(asm); - assembler.setFrameSize(frameMap.frameSize()); - assembler.targetMethod.setCustomStackAreaOffset(frameMap.offsetToCustomArea()); - } - return assembler; - } - - public boolean hasExceptionHandlers() { - return hasExceptionHandlers; - } - - public CiResult compile() { - CiTargetMethod targetMethod; - try { - emitHIR(); - emitLIR(); - targetMethod = emitCode(); - - if (C1XOptions.PrintMetrics) { - C1XMetrics.BytecodesCompiled += method.code().length; - } - } catch (CiBailout b) { - return new CiResult(null, b, stats); - } catch (Throwable t) { - if (C1XOptions.BailoutOnException) { - return new CiResult(null, new CiBailout("Exception while compiling: " + method, t), stats); - } else { - throw new RuntimeException(t); - } - } finally { - if (compiler.isObserved()) { - compiler.fireCompilationFinished(new CompilationEvent(this)); - } - } - - return new CiResult(targetMethod, null, stats); - } - - public IR emitHIR() { - hir = new IR(this); - hir.build(); - return hir; - } - - public void initFrameMap(int numberOfLocks) { - frameMap = this.compiler.backend.newFrameMap(method, numberOfLocks); - } - - private void emitLIR() { - if (C1XOptions.GenLIR) { - if (C1XOptions.PrintTimers) { - C1XTimers.LIR_CREATE.start(); - } - - initFrameMap(hir.maxLocks()); - - lirGenerator = compiler.backend.newLIRGenerator(this); - - for (LIRBlock begin : hir.linearScanOrder()) { - lirGenerator.doBlock(begin); - } - - if (C1XOptions.PrintTimers) { - C1XTimers.LIR_CREATE.stop(); - } - - if (C1XOptions.PrintLIR && !TTY.isSuppressed()) { - LIRList.printLIR(hir.linearScanOrder()); - } - - new LinearScan(this, hir, lirGenerator, frameMap()).allocate(); - } - } - - private CiTargetMethod emitCode() { - if (C1XOptions.GenLIR && C1XOptions.GenCode) { - final LIRAssembler lirAssembler = compiler.backend.newLIRAssembler(this); - lirAssembler.emitCode(hir.linearScanOrder()); - - // generate code for slow cases - lirAssembler.emitLocalStubs(); - - // generate deoptimization stubs - ArrayList deoptimizationStubs = lirGenerator.deoptimizationStubs(); - if (deoptimizationStubs != null) { - for (DeoptimizationStub stub : deoptimizationStubs) { - lirAssembler.emitDeoptizationStub(stub); - } - } - - // generate traps at the end of the method - lirAssembler.emitTraps(); - - CiTargetMethod targetMethod = assembler().finishTargetMethod(method, runtime, lirAssembler.registerRestoreEpilogueOffset, false); - if (assumptions.count() > 0) { - targetMethod.setAssumptions(assumptions); - } - - if (compiler.isObserved()) { - compiler.fireCompilationEvent(new CompilationEvent(this, "After code generation", graph, false, true, targetMethod)); - } - - if (C1XOptions.PrintTimers) { - C1XTimers.CODE_CREATE.stop(); - } - return targetMethod; - } - - return null; - } - - public int nextID() { - return nextID++; - } - - public static C1XCompilation compilation() { - C1XCompilation compilation = currentCompilation.get(); - assert compilation != null; - return compilation; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/C1XCompiler.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/C1XCompiler.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,167 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x; - -import java.util.*; - -import com.sun.c1x.debug.*; -import com.sun.c1x.globalstub.*; -import com.sun.c1x.observer.*; -import com.sun.c1x.target.*; -import com.sun.cri.ci.*; -import com.sun.cri.ri.*; -import com.sun.cri.xir.*; - -/** - * This class implements the compiler interface for C1X. - * - * @author Thomas Wuerthinger - * @author Ben L. Titzer - */ -public class C1XCompiler extends ObservableCompiler { - - public final Map stubs = new HashMap(); - - /** - * The target that this compiler has been configured for. - */ - public final CiTarget target; - - /** - * The runtime that this compiler has been configured for. - */ - public final RiRuntime runtime; - - /** - * The XIR generator that lowers Java operations to machine operations. - */ - public final RiXirGenerator xir; - - /** - * The backend that this compiler has been configured for. - */ - public final Backend backend; - - public final RiRegisterConfig globalStubRegisterConfig; - - public C1XCompiler(RiRuntime runtime, CiTarget target, RiXirGenerator xirGen, RiRegisterConfig globalStubRegisterConfig) { - this.runtime = runtime; - this.target = target; - this.xir = xirGen; - this.globalStubRegisterConfig = globalStubRegisterConfig; - this.backend = Backend.create(target.arch, this); - init(); - } - - public CiResult compileMethod(RiMethod method, int osrBCI, RiXirGenerator xirGenerator, CiStatistics stats) { - long startTime = 0; - int index = C1XMetrics.CompiledMethods++; - if (C1XOptions.PrintCompilation) { - TTY.print(String.format("C1X %4d %-70s %-45s | ", index, method.holder().name(), method.name())); - startTime = System.nanoTime(); - } - - CiResult result = null; - TTY.Filter filter = new TTY.Filter(C1XOptions.PrintFilter, method); - C1XCompilation compilation = new C1XCompilation(this, method, osrBCI, stats); - try { - result = compilation.compile(); - } finally { - filter.remove(); - compilation.close(); - if (C1XOptions.PrintCompilation && !TTY.isSuppressed()) { - long time = (System.nanoTime() - startTime) / 100000; - TTY.println(String.format("%3d.%dms", time / 10, time % 10)); - } - } - - return result; - } - - private void init() { - final List xirTemplateStubs = xir.buildTemplates(backend.newXirAssembler()); - final GlobalStubEmitter emitter = backend.newGlobalStubEmitter(); - - if (xirTemplateStubs != null) { - for (XirTemplate template : xirTemplateStubs) { - TTY.Filter filter = new TTY.Filter(C1XOptions.PrintFilter, template.name); - try { - stubs.put(template, emitter.emit(template, runtime)); - } finally { - filter.remove(); - } - } - } - - for (GlobalStub.Id id : GlobalStub.Id.values()) { - TTY.Filter suppressor = new TTY.Filter(C1XOptions.PrintFilter, id); - try { - stubs.put(id, emitter.emit(id, runtime)); - } finally { - suppressor.remove(); - } - } - - if (C1XOptions.PrintCFGToFile) { - addCompilationObserver(new CFGPrinterObserver()); - } - if (C1XOptions.PrintDOTGraphToFile) { - addCompilationObserver(new GraphvizPrinterObserver(false)); - } - if (C1XOptions.PrintDOTGraphToPdf) { - addCompilationObserver(new GraphvizPrinterObserver(true)); - } - if (C1XOptions.PrintIdealGraphLevel != 0) { - CompilationObserver observer; - if (C1XOptions.PrintIdealGraphFile) { - observer = new IdealGraphPrinterObserver(); - } else { - observer = new IdealGraphPrinterObserver(C1XOptions.PrintIdealGraphAddress, C1XOptions.PrintIdealGraphPort); - } - addCompilationObserver(observer); - } - } - - public GlobalStub lookupGlobalStub(GlobalStub.Id id) { - GlobalStub globalStub = stubs.get(id); - assert globalStub != null : "no stub for global stub id: " + id; - return globalStub; - } - - public GlobalStub lookupGlobalStub(XirTemplate template) { - GlobalStub globalStub = stubs.get(template); - assert globalStub != null : "no stub for XirTemplate: " + template; - return globalStub; - } - - public GlobalStub lookupGlobalStub(CiRuntimeCall runtimeCall) { - GlobalStub globalStub = stubs.get(runtimeCall); - if (globalStub == null) { - globalStub = backend.newGlobalStubEmitter().emit(runtimeCall, runtime); - stubs.put(runtimeCall, globalStub); - } - - assert globalStub != null : "could not find global stub for runtime call: " + runtimeCall; - return globalStub; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/C1XMetrics.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/C1XMetrics.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,132 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x; - -import java.lang.reflect.*; -import java.util.*; - -import com.sun.c1x.debug.*; - - -/** - * This class contains a number of fields that collect metrics about compilation, particularly - * the number of times certain optimizations are performed. - */ -public class C1XMetrics { - public static int CompiledMethods; - public static int TargetMethods; - public static int LocalValueNumberHits; - public static int ValueMapResizes; - public static int InlinedFinalizerChecks; - public static int InlineForcedMethods; - public static int InlineForbiddenMethods; - public static int InlinedJsrs; - public static int BlocksDeleted; - public static int BytecodesCompiled; - public static int CodeBytesEmitted; - public static int SafepointsEmitted; - public static int ExceptionHandlersEmitted; - public static int DataPatches; - public static int DirectCallSitesEmitted; - public static int IndirectCallSitesEmitted; - public static int HIRInstructions; - public static int LiveHIRInstructions; - public static int LIRInstructions; - public static int LIRVariables; - public static int LIRXIRInstructions; - public static int LIRMoveInstructions; - public static int LSRAIntervalsCreated; - public static int LSRASpills; - public static int LoadConstantIterations; - public static int CodeBufferCopies; - public static int UniqueValueIdsAssigned; - public static int FrameStatesCreated; - public static int FrameStateValuesCreated; - public static int NodesCanonicalized; - - public static void print() { - printClassFields(C1XMetrics.class); - - } - - public static void printClassFields(Class javaClass) { - final String className = javaClass.getSimpleName(); - TTY.println(className + " {"); - for (final Field field : javaClass.getFields()) { - printField(field, false); - } - TTY.println("}"); - } - - public static void printField(final Field field, boolean tabbed) { - final String fieldName = String.format("%35s", field.getName()); - try { - String prefix = tabbed ? "" : " " + fieldName + " = "; - String postfix = tabbed ? "\t" : "\n"; - if (field.getType() == int.class) { - TTY.print(prefix + field.getInt(null) + postfix); - } else if (field.getType() == boolean.class) { - TTY.print(prefix + field.getBoolean(null) + postfix); - } else if (field.getType() == float.class) { - TTY.print(prefix + field.getFloat(null) + postfix); - } else if (field.getType() == String.class) { - TTY.print(prefix + field.get(null) + postfix); - } else if (field.getType() == Map.class) { - Map m = (Map) field.get(null); - TTY.print(prefix + printMap(m) + postfix); - } else { - TTY.print(prefix + field.get(null) + postfix); - } - } catch (IllegalAccessException e) { - // do nothing. - } - } - - private static String printMap(Map m) { - StringBuilder sb = new StringBuilder(); - - List keys = new ArrayList(); - for (Object key : m.keySet()) { - keys.add((String) key); - } - Collections.sort(keys); - - for (String key : keys) { - sb.append(key); - sb.append("\t"); - sb.append(m.get(key)); - sb.append("\n"); - } - - return sb.toString(); - } - - private static void printField(String fieldName, long value) { - TTY.print(" " + fieldName + " = " + value + "\n"); - } - - private static void printField(String fieldName, double value) { - TTY.print(" " + fieldName + " = " + value + "\n"); - } -} - diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/C1XOptions.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/C1XOptions.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,133 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x; - -import com.sun.c1x.debug.TTY.*; - -/** - * This class encapsulates options that control the behavior of the C1X compiler. - * The help message for each option is specified by a {@linkplain #helpMap help map}. - * - * (tw) WARNING: Fields of this class are treated as final by Graal. - * - * @author Ben L. Titzer - */ -public final class C1XOptions { - - // Checkstyle: stop - private static final boolean ____ = false; - // Checkstyle: resume - - // inlining settings - public static boolean Inline = ____; - public static int MaximumInstructionCount = 37000; - public static float MaximumInlineRatio = 0.90f; - public static int MaximumInlineSize = 35; - public static int MaximumTrivialSize = 6; - public static int MaximumInlineLevel = 9; - public static int MaximumRecursiveInlineLevel = 2; - public static int MaximumDesiredSize = 8000; - public static int MaximumShortLoopSize = 5; - - // debugging settings - public static boolean VerifyPointerMaps = ____; - public static int MethodEndBreakpointGuards = 0; - public static boolean ZapStackOnMethodEntry = ____; - public static boolean StressLinearScan = ____; - public static boolean BailoutOnException = ____; - - /** - * See {@link Filter#Filter(String, Object)}. - */ - public static String PrintFilter = null; - - // printing settings - public static boolean PrintHIR = ____; - public static boolean PrintLIR = ____; - public static boolean PrintCFGToFile = ____; - - // DOT output settings - public static boolean PrintDOTGraphToFile = ____; - public static boolean PrintDOTGraphToPdf = ____; - public static boolean OmitDOTFrameStates = ____; - - // Ideal graph visualizer output settings - public static int PrintIdealGraphLevel = 0; - public static boolean PrintIdealGraphFile = ____; - public static String PrintIdealGraphAddress = "127.0.0.1"; - public static int PrintIdealGraphPort = 4444; - - // Other printing settings - public static boolean PrintMetrics = ____; - public static boolean PrintTimers = ____; - public static boolean PrintCompilation = ____; - public static boolean PrintXirTemplates = ____; - public static boolean PrintIRWithLIR = ____; - public static boolean PrintAssembly = ____; - public static boolean PrintCodeBytes = ____; - public static int PrintAssemblyBytesPerLine = 16; - public static int TraceLinearScanLevel = 0; - public static int TraceLIRGeneratorLevel = 0; - public static boolean TraceRelocation = ____; - public static boolean TraceLIRVisit = ____; - public static boolean TraceAssembler = ____; - public static boolean TraceInlining = ____; - public static boolean TraceDeadCodeElimination = ____; - public static int TraceBytecodeParserLevel = 0; - public static boolean QuietBailout = ____; - - // state merging settings - public static boolean AssumeVerifiedBytecode = ____; - - // Linear scan settings - public static boolean CopyPointerStackArguments = true; - - // Code generator settings - public static boolean GenLIR = true; - public static boolean GenCode = true; - - public static boolean UseConstDirectCall = false; - - public static boolean GenSpecialDivChecks = ____; - public static boolean GenAssertionCode = ____; - public static boolean AlignCallsForPatching = true; - public static boolean NullCheckUniquePc = ____; - public static boolean InvokeSnippetAfterArguments = ____; - public static boolean ResolveClassBeforeStaticInvoke = true; - - // Translating tableswitch instructions - public static int SequentialSwitchLimit = 4; - public static int RangeTestsSwitchDensity = 5; - - public static boolean DetailedAsserts = ____; - - // Runtime settings - public static int ReadPrefetchInstr = 0; - public static int StackShadowPages = 2; - - // Assembler settings - public static boolean CommentedAssembly = ____; - public static boolean PrintLIRWithAssembly = ____; - - public static boolean OptCanonicalizer = true; -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/C1XTimers.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/C1XTimers.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,82 +0,0 @@ -/* - * Copyright (c) 2009, 2009, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x; - -import com.sun.c1x.debug.*; - -/** - * This class contains timers that record the amount of time spent in various - * parts of the compiler. - * - * @author Christian Wimmer - */ -public enum C1XTimers { - HIR_CREATE("Create HIR"), - HIR_OPTIMIZE("Optimize HIR"), - NCE("Nullcheck elimination"), - LIR_CREATE("Create LIR"), - LIFETIME_ANALYSIS("Lifetime Analysis"), - LINEAR_SCAN("Linear Scan"), - RESOLUTION("Resolution"), - DEBUG_INFO("Create Debug Info"), - CODE_CREATE("Create Code"); - - private final String name; - private long start; - private long total; - - private C1XTimers(String name) { - this.name = name; - } - - public void start() { - start = System.nanoTime(); - } - - public void stop() { - total += System.nanoTime() - start; - } - - public static void reset() { - for (C1XTimers t : values()) { - t.total = 0; - } - } - - public static void print() { - long total = 0; - for (C1XTimers timer : C1XTimers.values()) { - total += timer.total; - } - if (total == 0) { - return; - } - - TTY.println(); - for (C1XTimers timer : C1XTimers.values()) { - TTY.println("%-20s: %7.4f s (%5.2f%%)", timer.name, timer.total / 1000000000.0, timer.total * 100.0 / total); - timer.total = 0; - } - TTY.println(); - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/alloc/ControlFlowOptimizer.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/alloc/ControlFlowOptimizer.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,260 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.alloc; - -import java.util.*; - -import com.sun.c1x.*; -import com.sun.c1x.graph.*; -import com.sun.c1x.ir.*; -import com.sun.c1x.lir.*; -import com.sun.c1x.util.*; -import com.sun.cri.ci.*; - -/** - * This class performs basic optimizations on the control flow graph after LIR generation. - */ -final class ControlFlowOptimizer { - - /** - * Performs control flow optimizations on the given IR graph. - * @param ir the IR graph that should be optimized - */ - public static void optimize(IR ir) { - ControlFlowOptimizer optimizer = new ControlFlowOptimizer(ir); - List code = ir.linearScanOrder(); - optimizer.reorderShortLoops(code); - optimizer.deleteEmptyBlocks(code); - optimizer.deleteUnnecessaryJumps(code); - optimizer.deleteJumpsToReturn(code); - } - - private final IR ir; - - private ControlFlowOptimizer(IR ir) { - this.ir = ir; - } - - private void reorderShortLoop(List code, LIRBlock headerBlock, int headerIdx) { - int i = headerIdx + 1; - int maxEnd = Math.min(headerIdx + C1XOptions.MaximumShortLoopSize, code.size()); - while (i < maxEnd && code.get(i).loopDepth() >= headerBlock.loopDepth()) { - i++; - } - - if (i == code.size() || code.get(i).loopDepth() < headerBlock.loopDepth()) { - int endIdx = i - 1; - LIRBlock endBlock = code.get(endIdx); - - if (endBlock.numberOfSux() == 1 && endBlock.suxAt(0) == headerBlock) { - // short loop from headerIdx to endIdx found . reorder blocks such that - // the headerBlock is the last block instead of the first block of the loop - - for (int j = headerIdx; j < endIdx; j++) { - code.set(j, code.get(j + 1)); - } - code.set(endIdx, headerBlock); - } - } - } - - private void reorderShortLoops(List code) { - for (int i = code.size() - 1; i >= 0; i--) { - LIRBlock block = code.get(i); - - if (block.isLinearScanLoopHeader()) { - reorderShortLoop(code, block, i); - } - } - - assert verify(code); - } - - // only blocks with exactly one successor can be deleted. Such blocks - // must always end with an unconditional branch to this successor - private boolean canDeleteBlock(LIRBlock block) { - if (block.numberOfSux() != 1 || - block == ir.startBlock || - block.suxAt(0) == block) { - return false; - } - - List instructions = block.lir().instructionsList(); - - assert instructions.size() >= 2 : "block must have label and branch"; - assert instructions.get(0).code == LIROpcode.Label : "first instruction must always be a label"; - assert instructions.get(instructions.size() - 1) instanceof LIRBranch : "last instruction must always be a branch but is " + instructions.get(instructions.size() - 1); - assert ((LIRBranch) instructions.get(instructions.size() - 1)).cond() == Condition.TRUE : "branch must be unconditional"; - assert ((LIRBranch) instructions.get(instructions.size() - 1)).block() == block.suxAt(0) : "branch target must be the successor"; - - // block must have exactly one successor - - return instructions.size() == 2 && instructions.get(instructions.size() - 1).info == null; - } - - private void deleteEmptyBlocks(List code) { - int oldPos = 0; - int newPos = 0; - int numBlocks = code.size(); - - while (oldPos < numBlocks) { - LIRBlock block = code.get(oldPos); - - if (canDeleteBlock(block)) { - LIRBlock newTarget = block.suxAt(0); - - // update the block references in any branching LIR instructions - for (LIRBlock pred : block.blockPredecessors()) { - for (LIRInstruction instr : pred.lir().instructionsList()) { - if (instr instanceof LIRBranch) { - ((LIRBranch) instr).substitute(block, newTarget); - } else if (instr instanceof LIRTableSwitch) { - ((LIRTableSwitch) instr).substitute(block, newTarget); - } - } - } - - // adjust successor and predecessor lists - block.replaceWith(newTarget); - C1XMetrics.BlocksDeleted++; - } else { - // adjust position of this block in the block list if blocks before - // have been deleted - if (newPos != oldPos) { - code.set(newPos, code.get(oldPos)); - } - newPos++; - } - oldPos++; - } - assert verify(code); - Util.truncate(code, newPos); - - assert verify(code); - } - - private void deleteUnnecessaryJumps(List code) { - // skip the last block because there a branch is always necessary - for (int i = code.size() - 2; i >= 0; i--) { - LIRBlock block = code.get(i); - List instructions = block.lir().instructionsList(); - - LIRInstruction lastOp = instructions.get(instructions.size() - 1); - if (lastOp.code == LIROpcode.Branch) { - assert lastOp instanceof LIRBranch : "branch must be of type LIRBranch"; - LIRBranch lastBranch = (LIRBranch) lastOp; - - assert lastBranch.block() != null : "last branch must always have a block as target"; - assert lastBranch.label() == lastBranch.block().label() : "must be equal"; - - if (lastBranch.info == null) { - if (lastBranch.block() == code.get(i + 1)) { - // delete last branch instruction - Util.truncate(instructions, instructions.size() - 1); - - } else { - LIRInstruction prevOp = instructions.get(instructions.size() - 2); - if (prevOp.code == LIROpcode.Branch || prevOp.code == LIROpcode.CondFloatBranch) { - assert prevOp instanceof LIRBranch : "branch must be of type LIRBranch"; - LIRBranch prevBranch = (LIRBranch) prevOp; - - if (prevBranch.block() == code.get(i + 1) && prevBranch.info == null) { - // eliminate a conditional branch to the immediate successor - prevBranch.changeBlock(lastBranch.block()); - prevBranch.negateCondition(); - Util.truncate(instructions, instructions.size() - 1); - } - } - } - } - } - } - - assert verify(code); - } - - private void deleteJumpsToReturn(List code) { - for (int i = code.size() - 1; i >= 0; i--) { - LIRBlock block = code.get(i); - List curInstructions = block.lir().instructionsList(); - LIRInstruction curLastOp = curInstructions.get(curInstructions.size() - 1); - - assert curInstructions.get(0).code == LIROpcode.Label : "first instruction must always be a label"; - if (curInstructions.size() == 2 && curLastOp.code == LIROpcode.Return) { - // the block contains only a label and a return - // if a predecessor ends with an unconditional jump to this block, then the jump - // can be replaced with a return instruction - // - // Note: the original block with only a return statement cannot be deleted completely - // because the predecessors might have other (conditional) jumps to this block. - // this may lead to unnecesary return instructions in the final code - - assert curLastOp.info == null : "return instructions do not have debug information"; - - assert curLastOp instanceof LIROp1 : "return must be LIROp1"; - CiValue returnOpr = ((LIROp1) curLastOp).operand(); - - for (int j = block.numberOfPreds() - 1; j >= 0; j--) { - LIRBlock pred = block.predAt(j); - List predInstructions = pred.lir().instructionsList(); - LIRInstruction predLastOp = predInstructions.get(predInstructions.size() - 1); - - if (predLastOp.code == LIROpcode.Branch) { - assert predLastOp instanceof LIRBranch : "branch must be LIRBranch"; - LIRBranch predLastBranch = (LIRBranch) predLastOp; - - if (predLastBranch.block() == block && predLastBranch.cond() == Condition.TRUE && predLastBranch.info == null) { - // replace the jump to a return with a direct return - // Note: currently the edge between the blocks is not deleted - predInstructions.set(predInstructions.size() - 1, new LIROp1(LIROpcode.Return, returnOpr)); - } - } - } - } - } - } - - private boolean verify(List code) { - for (LIRBlock block : code) { - List instructions = block.lir().instructionsList(); - - for (LIRInstruction instr : instructions) { - if (instr instanceof LIRBranch) { - LIRBranch opBranch = (LIRBranch) instr; - assert opBranch.block() == null || code.contains(opBranch.block()) : "missing successor branch from: " + block + " to: " + opBranch.block(); - assert opBranch.unorderedBlock() == null || code.contains(opBranch.unorderedBlock()) : "missing successor branch from: " + block + " to: " + opBranch.unorderedBlock(); - } - } - - for (LIRBlock sux : block.blockSuccessors()) { - assert code.contains(sux) : "missing successor from: " + block + "to: " + sux; - } - - for (LIRBlock pred : block.blockPredecessors()) { - assert code.contains(pred) : "missing predecessor from: " + block + "to: " + pred; - } - } - - return true; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/alloc/EdgeMoveOptimizer.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/alloc/EdgeMoveOptimizer.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,298 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.alloc; - -import java.util.*; - -import com.sun.c1x.*; -import com.sun.c1x.ir.*; -import com.sun.c1x.lir.*; - -/** - * This class optimizes moves, particularly those that result from eliminating SSA form. - * - * When a block has more than one predecessor, and all predecessors end with - * the {@linkplain #same(LIRInstruction, LIRInstruction) same} sequence of - * {@linkplain LIROpcode#Move move} instructions, then these sequences - * can be replaced with a single copy of the sequence at the beginning of the block. - * - * Similarly, when a block has more than one successor, then same sequences of - * moves at the beginning of the successors can be placed once at the end of - * the block. But because the moves must be inserted before all branch - * instructions, this works only when there is exactly one conditional branch - * at the end of the block (because the moves must be inserted before all - * branches, but after all compares). - * - * This optimization affects all kind of moves (reg->reg, reg->stack and - * stack->reg). Because this optimization works best when a block contains only - * a few moves, it has a huge impact on the number of blocks that are totally - * empty. - * - * @author Christian Wimmer (original HotSpot implementation) - * @author Thomas Wuerthinger - * @author Doug Simon - */ -final class EdgeMoveOptimizer { - - /** - * Optimizes moves on block edges. - * - * @param blockList a list of blocks whose moves should be optimized - */ - public static void optimize(List blockList) { - EdgeMoveOptimizer optimizer = new EdgeMoveOptimizer(); - - // ignore the first block in the list (index 0 is not processed) - for (int i = blockList.size() - 1; i >= 1; i--) { - LIRBlock block = blockList.get(i); - - if (block.numberOfPreds() > 1) { - optimizer.optimizeMovesAtBlockEnd(block); - } - if (block.numberOfSux() == 2) { - optimizer.optimizeMovesAtBlockBegin(block); - } - } - } - - private final List> edgeInstructionSeqences; - - private EdgeMoveOptimizer() { - edgeInstructionSeqences = new ArrayList>(4); - } - - /** - * Determines if two operations are both {@linkplain LIROpcode#Move moves} - * that have the same {@linkplain LIROp1#operand() source} and {@linkplain LIROp1#result() destination} - * operands and they have the same {@linkplain LIRInstruction#info debug info}. - * - * @param op1 the first instruction to compare - * @param op2 the second instruction to compare - * @return {@code true} if {@code op1} and {@code op2} are the same by the above algorithm - */ - private boolean same(LIRInstruction op1, LIRInstruction op2) { - assert op1 != null; - assert op2 != null; - - if (op1.code == LIROpcode.Move && op2.code == LIROpcode.Move) { - assert op1 instanceof LIROp1 : "move must be LIROp1"; - assert op2 instanceof LIROp1 : "move must be LIROp1"; - LIROp1 move1 = (LIROp1) op1; - LIROp1 move2 = (LIROp1) op2; - if (move1.info == move2.info && move1.operand().equals(move2.operand()) && move1.result().equals(move2.result())) { - // these moves are exactly equal and can be optimized - return true; - } - } - return false; - } - - /** - * Moves the longest {@linkplain #same common} subsequence at the end all - * predecessors of {@code block} to the start of {@code block}. - */ - private void optimizeMovesAtBlockEnd(LIRBlock block) { - if (block.isPredecessor(block)) { - // currently we can't handle this correctly. - return; - } - - // clear all internal data structures - edgeInstructionSeqences.clear(); - - int numPreds = block.numberOfPreds(); - assert numPreds > 1 : "do not call otherwise"; - - // setup a list with the LIR instructions of all predecessors - for (int i = 0; i < numPreds; i++) { - LIRBlock pred = block.predAt(i); - assert pred != null; - assert pred.lir() != null; - List predInstructions = pred.lir().instructionsList(); - - if (pred.numberOfSux() != 1) { - // this can happen with switch-statements where multiple edges are between - // the same blocks. - return; - } - - assert pred.suxAt(0) == block : "invalid control flow"; - assert predInstructions.get(predInstructions.size() - 1).code == LIROpcode.Branch : "block with successor must end with branch"; - assert predInstructions.get(predInstructions.size() - 1) instanceof LIRBranch : "branch must be LIROpBranch"; - assert ((LIRBranch) predInstructions.get(predInstructions.size() - 1)).cond() == Condition.TRUE : "block must end with unconditional branch"; - - if (predInstructions.get(predInstructions.size() - 1).info != null) { - // can not optimize instructions that have debug info - return; - } - - // ignore the unconditional branch at the end of the block - List seq = predInstructions.subList(0, predInstructions.size() - 1); - edgeInstructionSeqences.add(seq); - } - - // process lir-instructions while all predecessors end with the same instruction - while (true) { - List seq = edgeInstructionSeqences.get(0); - if (seq.isEmpty()) { - return; - } - - LIRInstruction op = last(seq); - for (int i = 1; i < numPreds; ++i) { - List otherSeq = edgeInstructionSeqences.get(i); - if (otherSeq.isEmpty() || !same(op, last(otherSeq))) { - return; - } - } - - // insert the instruction at the beginning of the current block - block.lir().insertBefore(1, op); - - // delete the instruction at the end of all predecessors - for (int i = 0; i < numPreds; i++) { - seq = edgeInstructionSeqences.get(i); - removeLast(seq); - } - } - } - - /** - * Moves the longest {@linkplain #same common} subsequence at the start of all - * successors of {@code block} to the end of {@code block} just prior to the - * branch instruction ending {@code block}. - */ - private void optimizeMovesAtBlockBegin(LIRBlock block) { - - edgeInstructionSeqences.clear(); - int numSux = block.numberOfSux(); - - List instructions = block.lir().instructionsList(); - - assert numSux == 2 : "method should not be called otherwise"; - assert instructions.get(instructions.size() - 1).code == LIROpcode.Branch : "block with successor must end with branch block=B" + block.blockID(); - assert instructions.get(instructions.size() - 1) instanceof LIRBranch : "branch must be LIROpBranch"; - assert ((LIRBranch) instructions.get(instructions.size() - 1)).cond() == Condition.TRUE : "block must end with unconditional branch"; - - if (instructions.get(instructions.size() - 1).info != null) { - // cannot optimize instructions when debug info is needed - return; - } - - LIRInstruction branch = instructions.get(instructions.size() - 2); - if (branch.info != null || (branch.code != LIROpcode.Branch && branch.code != LIROpcode.CondFloatBranch)) { - // not a valid case for optimization - // currently, only blocks that end with two branches (conditional branch followed - // by unconditional branch) are optimized - return; - } - - // now it is guaranteed that the block ends with two branch instructions. - // the instructions are inserted at the end of the block before these two branches - int insertIdx = instructions.size() - 2; - - if (C1XOptions.DetailedAsserts) { - for (int i = insertIdx - 1; i >= 0; i--) { - LIRInstruction op = instructions.get(i); - if ((op.code == LIROpcode.Branch || op.code == LIROpcode.CondFloatBranch) && ((LIRBranch) op).block() != null) { - throw new Error("block with two successors can have only two branch instructions"); - } - } - } - - // setup a list with the lir-instructions of all successors - for (int i = 0; i < numSux; i++) { - LIRBlock sux = block.suxAt(i); - List suxInstructions = sux.lir().instructionsList(); - - assert suxInstructions.get(0).code == LIROpcode.Label : "block must start with label"; - - if (sux.numberOfPreds() != 1) { - // this can happen with switch-statements where multiple edges are between - // the same blocks. - return; - } - assert sux.predAt(0) == block : "invalid control flow"; - - // ignore the label at the beginning of the block - List seq = suxInstructions.subList(1, suxInstructions.size()); - edgeInstructionSeqences.add(seq); - } - - // process LIR instructions while all successors begin with the same instruction - while (true) { - List seq = edgeInstructionSeqences.get(0); - if (seq.isEmpty()) { - return; - } - - LIRInstruction op = first(seq); - for (int i = 1; i < numSux; i++) { - List otherSeq = edgeInstructionSeqences.get(i); - if (otherSeq.isEmpty() || !same(op, first(otherSeq))) { - // these instructions are different and cannot be optimized . - // no further optimization possible - return; - } - } - - // insert instruction at end of current block - block.lir().insertBefore(insertIdx, op); - insertIdx++; - - // delete the instructions at the beginning of all successors - for (int i = 0; i < numSux; i++) { - seq = edgeInstructionSeqences.get(i); - removeFirst(seq); - } - } - } - - /** - * Gets the first element from a LIR instruction sequence. - */ - private static LIRInstruction first(List seq) { - return seq.get(0); - } - - /** - * Gets the last element from a LIR instruction sequence. - */ - private static LIRInstruction last(List seq) { - return seq.get(seq.size() - 1); - } - - /** - * Removes the first element from a LIR instruction sequence. - */ - private static void removeFirst(List seq) { - seq.remove(0); - } - - /** - * Removes the last element from a LIR instruction sequence. - */ - private static void removeLast(List seq) { - seq.remove(seq.size() - 1); - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/alloc/Interval.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/alloc/Interval.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1173 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.alloc; - -import java.util.*; - -import com.sun.c1x.*; -import com.sun.c1x.debug.*; -import com.sun.c1x.lir.*; -import com.sun.c1x.util.*; -import com.sun.cri.ci.*; - -/** - * Represents an interval in the {@linkplain LinearScan linear scan register allocator}. - * - * @author Thomas Wuerthinger - * @author Doug Simon - */ -public final class Interval { - - /** - * A pair of intervals. - */ - static final class Pair { - public final Interval first; - public final Interval second; - public Pair(Interval first, Interval second) { - this.first = first; - this.second = second; - } - } - - /** - * A set of interval lists, one per {@linkplain RegisterBinding binding} type. - */ - static final class RegisterBindingLists { - - /** - * List of intervals whose binding is currently {@link RegisterBinding#Fixed}. - */ - public Interval fixed; - - /** - * List of intervals whose binding is currently {@link RegisterBinding#Any}. - */ - public Interval any; - - public RegisterBindingLists(Interval fixed, Interval any) { - this.fixed = fixed; - this.any = any; - } - - /** - * Gets the list for a specified binding. - * - * @param binding specifies the list to be returned - * @return the list of intervals whose binding is {@code binding} - */ - public Interval get(RegisterBinding binding) { - if (binding == RegisterBinding.Any) { - return any; - } - assert binding == RegisterBinding.Fixed; - return fixed; - } - - /** - * Sets the list for a specified binding. - * - * @param binding specifies the list to be replaced - * @param a list of intervals whose binding is {@code binding} - */ - public void set(RegisterBinding binding, Interval list) { - assert list != null; - if (binding == RegisterBinding.Any) { - any = list; - } else { - assert binding == RegisterBinding.Fixed; - fixed = list; - } - } - - /** - * Adds an interval to a list sorted by {@linkplain Interval#currentFrom() current from} positions. - * - * @param binding specifies the list to be updated - * @param interval the interval to add - */ - public void addToListSortedByCurrentFromPositions(RegisterBinding binding, Interval interval) { - Interval list = get(binding); - Interval prev = null; - Interval cur = list; - while (cur.currentFrom() < interval.currentFrom()) { - prev = cur; - cur = cur.next; - } - Interval result = list; - if (prev == null) { - // add to head of list - result = interval; - } else { - // add before 'cur' - prev.next = interval; - } - interval.next = cur; - set(binding, result); - } - - /** - * Adds an interval to a list sorted by {@linkplain Interval#from() start} positions and - * {@linkplain Interval#firstUsage(RegisterPriority) first usage} positions. - * - * @param binding specifies the list to be updated - * @param interval the interval to add - */ - public void addToListSortedByStartAndUsePositions(RegisterBinding binding, Interval interval) { - Interval list = get(binding); - Interval prev = null; - Interval cur = list; - while (cur.from() < interval.from() || (cur.from() == interval.from() && cur.firstUsage(RegisterPriority.None) < interval.firstUsage(RegisterPriority.None))) { - prev = cur; - cur = cur.next; - } - if (prev == null) { - list = interval; - } else { - prev.next = interval; - } - interval.next = cur; - set(binding, list); - } - - /** - * Removes an interval from a list. - * - * @param binding specifies the list to be updated - * @param interval the interval to remove - */ - public void remove(RegisterBinding binding, Interval i) { - Interval list = get(binding); - Interval prev = null; - Interval cur = list; - while (cur != i) { - assert cur != null && cur != Interval.EndMarker : "interval has not been found in list: " + i; - prev = cur; - cur = cur.next; - } - if (prev == null) { - set(binding, cur.next); - } else { - prev.next = cur.next; - } - } - } - - /** - * Constants denoting the register usage priority for an interval. - * The constants are declared in increasing order of priority are - * are used to optimize spilling when multiple overlapping intervals - * compete for limited registers. - */ - enum RegisterPriority { - /** - * No special reason for an interval to be allocated a register. - */ - None, - - /** - * Priority level for intervals live at the end of a loop. - */ - LiveAtLoopEnd, - - /** - * Priority level for intervals that should be allocated to a register. - */ - ShouldHaveRegister, - - /** - * Priority level for intervals that must be allocated to a register. - */ - MustHaveRegister; - - public static final RegisterPriority[] VALUES = values(); - - /** - * Determines if this priority is higher than or equal to a given priority. - */ - public boolean greaterEqual(RegisterPriority other) { - return ordinal() >= other.ordinal(); - } - - /** - * Determines if this priority is lower than a given priority. - */ - public boolean lessThan(RegisterPriority other) { - return ordinal() < other.ordinal(); - } - } - - /** - * Constants denoting whether an interval is bound to a specific register. This models - * platform dependencies on register usage for certain instructions. - */ - enum RegisterBinding { - /** - * Interval is bound to a specific register as required by the platform. - */ - Fixed, - - /** - * Interval has no specific register requirements. - */ - Any; - - public static final RegisterBinding[] VALUES = values(); - } - - /** - * Constants denoting the linear-scan states an interval may be in with respect to the - * {@linkplain Interval#from() start} {@code position} of the interval being processed. - */ - enum State { - /** - * An interval that starts after {@code position}. - */ - Unhandled, - - /** - * An interval that {@linkplain Interval#covers covers} {@code position} and has an assigned register. - */ - Active, - - /** - * An interval that starts before and ends after {@code position} but does not - * {@linkplain Interval#covers cover} it due to a lifetime hole. - */ - Inactive, - - /** - * An interval that ends before {@code position} or is spilled to memory. - */ - Handled; - } - - /** - * Constants used in optimization of spilling of an interval. - */ - enum SpillState { - /** - * Starting state of calculation: no definition found yet. - */ - NoDefinitionFound, - - /** - * One definition has already been found. Two consecutive definitions are treated as one - * (e.g. a consecutive move and add because of two-operand LIR form). - * The position of this definition is given by {@link Interval#spillDefinitionPos()}. - */ - NoSpillStore, - - /** - * One spill move has already been inserted. - */ - OneSpillStore, - - /** - * The interval should be stored immediately after its definition to prevent - * multiple redundant stores. - */ - StoreAtDefinition, - - /** - * The interval starts in memory (e.g. method parameter), so a store is never necessary. - */ - StartInMemory, - - /** - * The interval has more than one definition (e.g. resulting from phi moves), so stores - * to memory are not optimized. - */ - NoOptimization - } - - /** - * List of use positions. Each entry in the list records the use position and register - * priority associated with the use position. The entries in the list are in descending - * order of use position. - * - * @author Doug Simon - */ - public static final class UsePosList { - private IntList list; - - /** - * Creates a use list. - * - * @param initialCapacity the initial capacity of the list in terms of entries - */ - public UsePosList(int initialCapacity) { - list = new IntList(initialCapacity * 2); - } - - private UsePosList(IntList list) { - this.list = list; - } - - /** - * Splits this list around a given position. All entries in this list with a use position greater or equal than - * {@code splitPos} are removed from this list and added to the returned list. - * - * @param splitPos the position for the split - * @return a use position list containing all entries removed from this list that have a use position greater or equal - * than {@code splitPos} - */ - public UsePosList splitAt(int splitPos) { - int i = size() - 1; - int len = 0; - while (i >= 0 && usePos(i) < splitPos) { - --i; - len += 2; - } - int listSplitIndex = (i + 1) * 2; - IntList childList = list; - list = IntList.copy(this.list, listSplitIndex, len); - childList.setSize(listSplitIndex); - UsePosList child = new UsePosList(childList); - return child; - } - - /** - * Gets the use position at a specified index in this list. - * - * @param index the index of the entry for which the use position is returned - * @return the use position of entry {@code index} in this list - */ - public int usePos(int index) { - return list.get(index << 1); - } - - /** - * Gets the register priority for the use position at a specified index in this list. - * - * @param index the index of the entry for which the register priority is returned - * @return the register priority of entry {@code index} in this list - */ - public RegisterPriority registerPriority(int index) { - return RegisterPriority.VALUES[list.get((index << 1) + 1)]; - } - - public void add(int usePos, RegisterPriority registerPriority) { - assert list.size() == 0 || usePos(size() - 1) > usePos; - list.add(usePos); - list.add(registerPriority.ordinal()); - } - - public int size() { - return list.size() >> 1; - } - - public void removeLowestUsePos() { - list.setSize(list.size() - 2); - } - - public void setRegisterPriority(int index, RegisterPriority registerPriority) { - list.set(index * 2, registerPriority.ordinal()); - } - - @Override - public String toString() { - StringBuilder buf = new StringBuilder("["); - for (int i = size() - 1; i >= 0; --i) { - if (buf.length() != 1) { - buf.append(", "); - } - RegisterPriority prio = registerPriority(i); - buf.append(usePos(i)).append(" -> ").append(prio.ordinal()).append(':').append(prio); - } - return buf.append("]").toString(); - } - } - - /** - * The {@linkplain CiRegisterValue register} or {@linkplain CiVariable variable} for this interval prior to register allocation. - */ - public final CiValue operand; - - /** - * The {@linkplain OperandPool#operandNumber(CiValue) operand number} for this interval's {@linkplain #operand operand}. - */ - public final int operandNumber; - - /** - * The {@linkplain CiRegisterValue register}, {@linkplain CiStackSlot spill slot} or {@linkplain CiAddress address} assigned to this interval. - */ - private CiValue location; - - /** - * The stack slot to which all splits of this interval are spilled if necessary. - */ - private CiStackSlot spillSlot; - - /** - * The kind of this interval. - * Only valid if this is a {@linkplain #isVariable() variable}. - */ - private CiKind kind; - - /** - * The head of the list of ranges describing this interval. This list is sorted by {@linkplain LIRInstruction#id instruction ids}. - */ - private Range first; - - /** - * List of (use-positions, register-priorities) pairs, sorted by use-positions. - */ - private UsePosList usePosList; - - /** - * Iterator used to traverse the ranges of an interval. - */ - private Range current; - - /** - * Link to next interval in a sorted list of intervals that ends with {@link #EndMarker}. - */ - Interval next; - - /** - * The linear-scan state of this interval. - */ - State state; - - private int cachedTo; // cached value: to of last range (-1: not cached) - - /** - * The interval from which this one is derived. If this is a {@linkplain #isSplitParent() split parent}, it points to itself. - */ - private Interval splitParent; - - /** - * List of all intervals that are split off from this interval. This is only used if this is a {@linkplain #isSplitParent() split parent}. - */ - private List splitChildren = Collections.emptyList(); - - /** - * Current split child that has been active or inactive last (always stored in split parents). - */ - private Interval currentSplitChild; - - /** - * Specifies if move is inserted between currentSplitChild and this interval when interval gets active the first time. - */ - private boolean insertMoveWhenActivated; - - /** - * For spill move optimization. - */ - private SpillState spillState; - - /** - * Position where this interval is defined (if defined only once). - */ - private int spillDefinitionPos; - - /** - * This interval should be assigned the same location as the hint interval. - */ - private Interval locationHint; - - void assignLocation(CiValue location) { - if (location.isRegister()) { - assert this.location == null : "cannot re-assign location for " + this; - if (location.kind == CiKind.Illegal && kind != CiKind.Illegal) { - location = location.asRegister().asValue(kind); - } - } else { - assert this.location == null || this.location.isRegister() : "cannot re-assign location for " + this; - assert location.isStackSlot(); - assert location.kind != CiKind.Illegal; - assert location.kind == this.kind; - } - this.location = location; - } - - /** - * Gets the {@linkplain CiRegisterValue register}, {@linkplain CiStackSlot spill slot} or {@linkplain CiAddress address} assigned to this interval. - */ - public CiValue location() { - return location; - } - - public CiKind kind() { - assert !operand.isRegister() : "cannot access type for fixed interval"; - return kind; - } - - void setKind(CiKind kind) { - assert operand.isRegister() || this.kind == CiKind.Illegal || this.kind == kind : "overwriting existing type"; - assert kind == kind.stackKind() || kind == CiKind.Short : "these kinds should have int type registers"; - this.kind = kind; - } - - public Range first() { - return first; - } - - int from() { - return first.from; - } - - int to() { - if (cachedTo == -1) { - cachedTo = calcTo(); - } - assert cachedTo == calcTo() : "invalid cached value"; - return cachedTo; - } - - int numUsePositions() { - return usePosList.size(); - } - - void setLocationHint(Interval interval) { - locationHint = interval; - } - - boolean isSplitParent() { - return splitParent == this; - } - - boolean isSplitChild() { - return splitParent != this; - } - - /** - * Gets the split parent for this interval. - */ - public Interval splitParent() { - assert splitParent.isSplitParent() : "not a split parent: " + this; - return splitParent; - } - - /** - * Gets the canonical spill slot for this interval. - */ - CiStackSlot spillSlot() { - return splitParent().spillSlot; - } - - void setSpillSlot(CiStackSlot slot) { - assert splitParent().spillSlot == null : "connot overwrite existing spill slot"; - splitParent().spillSlot = slot; - } - - Interval currentSplitChild() { - return splitParent().currentSplitChild; - } - - void makeCurrentSplitChild() { - splitParent().currentSplitChild = this; - } - - boolean insertMoveWhenActivated() { - return insertMoveWhenActivated; - } - - void setInsertMoveWhenActivated(boolean b) { - insertMoveWhenActivated = b; - } - - // for spill optimization - public SpillState spillState() { - return splitParent().spillState; - } - - int spillDefinitionPos() { - return splitParent().spillDefinitionPos; - } - - void setSpillState(SpillState state) { - assert state.ordinal() >= spillState().ordinal() : "state cannot decrease"; - splitParent().spillState = state; - } - - void setSpillDefinitionPos(int pos) { - assert spillDefinitionPos() == -1 : "cannot set the position twice"; - splitParent().spillDefinitionPos = pos; - } - - // returns true if this interval has a shadow copy on the stack that is always correct - boolean alwaysInMemory() { - return splitParent().spillState == SpillState.StoreAtDefinition || splitParent().spillState == SpillState.StartInMemory; - } - - void removeFirstUsePos() { - usePosList.removeLowestUsePos(); - } - - // test intersection - boolean intersects(Interval i) { - return first.intersects(i.first); - } - - int intersectsAt(Interval i) { - return first.intersectsAt(i.first); - } - - // range iteration - void rewindRange() { - current = first; - } - - void nextRange() { - assert this != EndMarker : "not allowed on sentinel"; - current = current.next; - } - - int currentFrom() { - return current.from; - } - - int currentTo() { - return current.to; - } - - boolean currentAtEnd() { - return current == Range.EndMarker; - } - - boolean currentIntersects(Interval it) { - return current.intersects(it.current); - } - - int currentIntersectsAt(Interval it) { - return current.intersectsAt(it.current); - } - - /** - * Sentinel interval to denote the end of an interval list. - */ - static final Interval EndMarker = new Interval(CiValue.IllegalValue, -1); - - Interval(CiValue operand, int operandNumber) { - C1XMetrics.LSRAIntervalsCreated++; - assert operand != null; - this.operand = operand; - this.operandNumber = operandNumber; - if (operand.isRegister()) { - location = operand; - } else { - assert operand.isIllegal() || operand.isVariable(); - } - this.kind = CiKind.Illegal; - this.first = Range.EndMarker; - this.usePosList = new UsePosList(4); - this.current = Range.EndMarker; - this.next = EndMarker; - this.cachedTo = -1; - this.spillState = SpillState.NoDefinitionFound; - this.spillDefinitionPos = -1; - splitParent = this; - currentSplitChild = this; - } - - int calcTo() { - assert first != Range.EndMarker : "interval has no range"; - - Range r = first; - while (r.next != Range.EndMarker) { - r = r.next; - } - return r.to; - } - - // consistency check of split-children - boolean checkSplitChildren() { - if (!splitChildren.isEmpty()) { - assert isSplitParent() : "only split parents can have children"; - - for (int i = 0; i < splitChildren.size(); i++) { - Interval i1 = splitChildren.get(i); - - assert i1.splitParent() == this : "not a split child of this interval"; - assert i1.kind() == kind() : "must be equal for all split children"; - assert i1.spillSlot() == spillSlot() : "must be equal for all split children"; - - for (int j = i + 1; j < splitChildren.size(); j++) { - Interval i2 = splitChildren.get(j); - - assert i1.operand != i2.operand : "same register number"; - - if (i1.from() < i2.from()) { - assert i1.to() <= i2.from() && i1.to() < i2.to() : "intervals overlapping"; - } else { - assert i2.from() < i1.from() : "intervals start at same opId"; - assert i2.to() <= i1.from() && i2.to() < i1.to() : "intervals overlapping"; - } - } - } - } - - return true; - } - - public Interval locationHint(boolean searchSplitChild, LinearScan allocator) { - if (!searchSplitChild) { - return locationHint; - } - - if (locationHint != null) { - assert locationHint.isSplitParent() : "ony split parents are valid hint registers"; - - if (locationHint.location != null && locationHint.location.isRegister()) { - return locationHint; - } else if (!locationHint.splitChildren.isEmpty()) { - // search the first split child that has a register assigned - int len = locationHint.splitChildren.size(); - for (int i = 0; i < len; i++) { - Interval interval = locationHint.splitChildren.get(i); - if (interval.location != null && interval.location.isRegister()) { - return interval; - } - } - } - } - - // no hint interval found that has a register assigned - return null; - } - - Interval getSplitChildAtOpId(int opId, LIRInstruction.OperandMode mode, LinearScan allocator) { - assert isSplitParent() : "can only be called for split parents"; - assert opId >= 0 : "invalid opId (method cannot be called for spill moves)"; - - if (splitChildren.isEmpty()) { - assert this.covers(opId, mode) : this + " does not cover " + opId; - return this; - } else { - Interval result = null; - int len = splitChildren.size(); - - // in outputMode, the end of the interval (opId == cur.to()) is not valid - int toOffset = (mode == LIRInstruction.OperandMode.Output ? 0 : 1); - - int i; - for (i = 0; i < len; i++) { - Interval cur = splitChildren.get(i); - if (cur.from() <= opId && opId < cur.to() + toOffset) { - if (i > 0) { - // exchange current split child to start of list (faster access for next call) - Util.atPutGrow(splitChildren, i, splitChildren.get(0), null); - Util.atPutGrow(splitChildren, 0, cur, null); - } - - // interval found - result = cur; - break; - } - } - - assert checkSplitChild(result, opId, allocator, toOffset, mode); - return result; - } - } - - private boolean checkSplitChild(Interval result, int opId, LinearScan allocator, int toOffset, LIRInstruction.OperandMode mode) { - if (result == null) { - // this is an error - StringBuilder msg = new StringBuilder(this.toString()).append(" has no child at ").append(opId); - if (!splitChildren.isEmpty()) { - Interval first = splitChildren.get(0); - Interval last = splitChildren.get(splitChildren.size() - 1); - msg.append(" (first = ").append(first).append(", last = ").append(last).append(")"); - } - throw new CiBailout("Linear Scan Error: " + msg); - } - - if (!splitChildren.isEmpty()) { - for (Interval interval : splitChildren) { - if (interval != result && interval.from() <= opId && opId < interval.to() + toOffset) { - TTY.println(String.format("two valid result intervals found for opId %d: %d and %d", opId, result.operandNumber, interval.operandNumber)); - TTY.println(result.logString(allocator)); - TTY.println(interval.logString(allocator)); - throw new CiBailout("two valid result intervals found"); - } - } - } - assert result.covers(opId, mode) : "opId not covered by interval"; - return true; - } - - // returns the last split child that ends before the given opId - Interval getSplitChildBeforeOpId(int opId) { - assert opId >= 0 : "invalid opId"; - - Interval parent = splitParent(); - Interval result = null; - - assert !parent.splitChildren.isEmpty() : "no split children available"; - int len = parent.splitChildren.size(); - - for (int i = len - 1; i >= 0; i--) { - Interval cur = parent.splitChildren.get(i); - if (cur.to() <= opId && (result == null || result.to() < cur.to())) { - result = cur; - } - } - - assert result != null : "no split child found"; - return result; - } - - // checks if opId is covered by any split child - boolean splitChildCovers(int opId, LIRInstruction.OperandMode mode) { - assert isSplitParent() : "can only be called for split parents"; - assert opId >= 0 : "invalid opId (method can not be called for spill moves)"; - - if (splitChildren.isEmpty()) { - // simple case if interval was not split - return covers(opId, mode); - - } else { - // extended case: check all split children - int len = splitChildren.size(); - for (int i = 0; i < len; i++) { - Interval cur = splitChildren.get(i); - if (cur.covers(opId, mode)) { - return true; - } - } - return false; - } - } - - // Note: use positions are sorted descending . first use has highest index - int firstUsage(RegisterPriority minRegisterPriority) { - assert operand.isVariable() : "cannot access use positions for fixed intervals"; - - for (int i = usePosList.size() - 1; i >= 0; --i) { - RegisterPriority registerPriority = usePosList.registerPriority(i); - if (registerPriority.greaterEqual(minRegisterPriority)) { - return usePosList.usePos(i); - } - } - return Integer.MAX_VALUE; - } - - int nextUsage(RegisterPriority minRegisterPriority, int from) { - assert operand.isVariable() : "cannot access use positions for fixed intervals"; - - for (int i = usePosList.size() - 1; i >= 0; --i) { - int usePos = usePosList.usePos(i); - if (usePos >= from && usePosList.registerPriority(i).greaterEqual(minRegisterPriority)) { - return usePos; - } - } - return Integer.MAX_VALUE; - } - - int nextUsageExact(RegisterPriority exactRegisterPriority, int from) { - assert operand.isVariable() : "cannot access use positions for fixed intervals"; - - for (int i = usePosList.size() - 1; i >= 0; --i) { - int usePos = usePosList.usePos(i); - if (usePos >= from && usePosList.registerPriority(i) == exactRegisterPriority) { - return usePos; - } - } - return Integer.MAX_VALUE; - } - - int previousUsage(RegisterPriority minRegisterPriority, int from) { - assert operand.isVariable() : "cannot access use positions for fixed intervals"; - - int prev = 0; - for (int i = usePosList.size() - 1; i >= 0; --i) { - int usePos = usePosList.usePos(i); - if (usePos > from) { - return prev; - } - if (usePosList.registerPriority(i).greaterEqual(minRegisterPriority)) { - prev = usePos; - } - } - return prev; - } - - void addUsePos(int pos, RegisterPriority registerPriority) { - assert covers(pos, LIRInstruction.OperandMode.Input) : "use position not covered by live range"; - - // do not add use positions for precolored intervals because they are never used - if (registerPriority != RegisterPriority.None && operand.isVariable()) { - if (C1XOptions.DetailedAsserts) { - for (int i = 0; i < usePosList.size(); i++) { - assert pos <= usePosList.usePos(i) : "already added a use-position with lower position"; - if (i > 0) { - assert usePosList.usePos(i) < usePosList.usePos(i - 1) : "not sorted descending"; - } - } - } - - // Note: addUse is called in descending order, so list gets sorted - // automatically by just appending new use positions - int len = usePosList.size(); - if (len == 0 || usePosList.usePos(len - 1) > pos) { - usePosList.add(pos, registerPriority); - } else if (usePosList.registerPriority(len - 1).lessThan(registerPriority)) { - assert usePosList.usePos(len - 1) == pos : "list not sorted correctly"; - usePosList.setRegisterPriority(len - 1, registerPriority); - } - } - } - - void addRange(int from, int to) { - assert from < to : "invalid range"; - assert first() == Range.EndMarker || to < first().next.from : "not inserting at begin of interval"; - assert from <= first().to : "not inserting at begin of interval"; - - if (first.from <= to) { - assert first != Range.EndMarker; - // join intersecting ranges - first.from = Math.min(from, first().from); - first.to = Math.max(to, first().to); - } else { - // insert new range - first = new Range(from, to, first()); - } - } - - Interval newSplitChild(LinearScan allocator) { - // allocate new interval - Interval parent = splitParent(); - Interval result = allocator.createDerivedInterval(parent); - result.setKind(kind()); - - result.splitParent = parent; - result.setLocationHint(parent); - - // insert new interval in children-list of parent - if (parent.splitChildren.isEmpty()) { - assert isSplitParent() : "list must be initialized at first split"; - - // Create new non-shared list - parent.splitChildren = new ArrayList(4); - parent.splitChildren.add(this); - } - parent.splitChildren.add(result); - - return result; - } - - /** - * Splits this interval at a specified position and returns the remainder as a new child interval - * of this interval's {@linkplain #splitParent() parent} interval. - *

- * When an interval is split, a bi-directional link is established between the original parent - * interval and the children intervals that are split off this interval. - * When a split child is split again, the new created interval is a direct child - * of the original parent. That is, there is no tree of split children stored, just a flat list. - * All split children are spilled to the same {@linkplain #spillSlot spill slot}. - * - * @param splitPos the position at which to split this interval - * @param allocator the register allocator context - * @return the child interval split off from this interval - */ - Interval split(int splitPos, LinearScan allocator) { - assert operand.isVariable() : "cannot split fixed intervals"; - - // allocate new interval - Interval result = newSplitChild(allocator); - - // split the ranges - Range prev = null; - Range cur = first; - while (cur != Range.EndMarker && cur.to <= splitPos) { - prev = cur; - cur = cur.next; - } - assert cur != Range.EndMarker : "split interval after end of last range"; - - if (cur.from < splitPos) { - result.first = new Range(splitPos, cur.to, cur.next); - cur.to = splitPos; - cur.next = Range.EndMarker; - - } else { - assert prev != null : "split before start of first range"; - result.first = cur; - prev.next = Range.EndMarker; - } - result.current = result.first; - cachedTo = -1; // clear cached value - - // split list of use positions - result.usePosList = usePosList.splitAt(splitPos); - - if (C1XOptions.DetailedAsserts) { - for (int i = 0; i < usePosList.size(); i++) { - assert usePosList.usePos(i) < splitPos; - } - for (int i = 0; i < result.usePosList.size(); i++) { - assert result.usePosList.usePos(i) >= splitPos; - } - } - return result; - } - - /** - * Splits this interval at a specified position and returns - * the head as a new interval (this interval is the tail). - * - * Currently, only the first range can be split, and the new interval must not have split positions - */ - Interval splitFromStart(int splitPos, LinearScan allocator) { - assert operand.isVariable() : "cannot split fixed intervals"; - assert splitPos > from() && splitPos < to() : "can only split inside interval"; - assert splitPos > first.from && splitPos <= first.to : "can only split inside first range"; - assert firstUsage(RegisterPriority.None) > splitPos : "can not split when use positions are present"; - - // allocate new interval - Interval result = newSplitChild(allocator); - - // the new interval has only one range (checked by assertion above, - // so the splitting of the ranges is very simple - result.addRange(first.from, splitPos); - - if (splitPos == first.to) { - assert first.next != Range.EndMarker : "must not be at end"; - first = first.next; - } else { - first.from = splitPos; - } - - return result; - } - - // returns true if the opId is inside the interval - boolean covers(int opId, LIRInstruction.OperandMode mode) { - Range cur = first; - - while (cur != Range.EndMarker && cur.to < opId) { - cur = cur.next; - } - if (cur != Range.EndMarker) { - assert cur.to != cur.next.from : "ranges not separated"; - - if (mode == LIRInstruction.OperandMode.Output) { - return cur.from <= opId && opId < cur.to; - } else { - return cur.from <= opId && opId <= cur.to; - } - } - return false; - } - - // returns true if the interval has any hole between holeFrom and holeTo - // (even if the hole has only the length 1) - boolean hasHoleBetween(int holeFrom, int holeTo) { - assert holeFrom < holeTo : "check"; - assert from() <= holeFrom && holeTo <= to() : "index out of interval"; - - Range cur = first; - while (cur != Range.EndMarker) { - assert cur.to < cur.next.from : "no space between ranges"; - - // hole-range starts before this range . hole - if (holeFrom < cur.from) { - return true; - - // hole-range completely inside this range . no hole - } else { - if (holeTo <= cur.to) { - return false; - - // overlapping of hole-range with this range . hole - } else { - if (holeFrom <= cur.to) { - return true; - } - } - } - - cur = cur.next; - } - - return false; - } - - @Override - public String toString() { - String from = "?"; - String to = "?"; - if (first != null && first != Range.EndMarker) { - from = String.valueOf(from()); - to = String.valueOf(to()); - } - String location = this.location == null ? "" : "@" + this.location.name(); - return operandNumber + ":" + operand + (operand.isRegister() ? "" : location) + "[" + from + "," + to + "]"; - } - - /** - * Gets the use position information for this interval. - */ - public UsePosList usePosList() { - return usePosList; - } - - /** - * Gets a single line string for logging the details of this interval to a log stream. - * - * @param allocator the register allocator context - */ - public String logString(LinearScan allocator) { - StringBuilder buf = new StringBuilder(100); - buf.append(operandNumber).append(':').append(operand).append(' '); - if (!operand.isRegister()) { - if (location != null) { - buf.append("location{").append(location).append("} "); - } - } - - buf.append("hints{").append(splitParent.operandNumber); - Interval hint = locationHint(false, allocator); - if (hint != null && hint.operandNumber != splitParent.operandNumber) { - buf.append(", ").append(hint.operandNumber); - } - buf.append("} ranges{"); - - // print ranges - Range cur = first; - while (cur != Range.EndMarker) { - if (cur != first) { - buf.append(", "); - } - buf.append(cur); - cur = cur.next; - assert cur != null : "range list not closed with range sentinel"; - } - buf.append("} uses{"); - - // print use positions - int prev = 0; - for (int i = usePosList.size() - 1; i >= 0; --i) { - assert prev < usePosList.usePos(i) : "use positions not sorted"; - if (i != usePosList.size() - 1) { - buf.append(", "); - } - buf.append(usePosList.usePos(i)).append(':').append(usePosList.registerPriority(i)); - prev = usePosList.usePos(i); - } - return buf.append("} spill-state{").append(spillState()).append("}").toString(); - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/alloc/IntervalWalker.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/alloc/IntervalWalker.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,246 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.alloc; - -import com.sun.c1x.*; -import com.sun.c1x.alloc.Interval.*; -import com.sun.c1x.debug.*; - -/** - * - * @author Thomas Wuerthinger - */ -public class IntervalWalker { - - protected final C1XCompilation compilation; - protected final LinearScan allocator; - - /** - * Sorted list of intervals, not live before the current position. - */ - RegisterBindingLists unhandledLists; - - /** - * Sorted list of intervals, live at the current position. - */ - RegisterBindingLists activeLists; - - /** - * Sorted list of intervals in a life time hole at the current position. - */ - RegisterBindingLists inactiveLists; - - /** - * The current interval (taken from the unhandled list) being processed. - */ - protected Interval current; - - /** - * The current position (intercept point through the intervals). - */ - protected int currentPosition; - - /** - * The binding of the current interval being processed. - */ - protected RegisterBinding currentBinding; - - /** - * Processes the {@linkplain #current} interval in an attempt to allocate a physical - * register to it and thus allow it to be moved to a list of {@linkplain #activeLists active} intervals. - * - * @return {@code true} if a register was allocated to the {@linkplain #current} interval - */ - boolean activateCurrent() { - return true; - } - - void walkBefore(int lirOpId) { - walkTo(lirOpId - 1); - } - - void walk() { - walkTo(Integer.MAX_VALUE); - } - - /** - * Creates a new interval walker. - * - * @param allocator the register allocator context - * @param unhandledFixed the list of unhandled {@linkplain RegisterBinding#Fixed fixed} intervals - * @param unhandledAny the list of unhandled {@linkplain RegisterBinding#Any non-fixed} intervals - */ - IntervalWalker(LinearScan allocator, Interval unhandledFixed, Interval unhandledAny) { - this.compilation = allocator.compilation; - this.allocator = allocator; - - unhandledLists = new RegisterBindingLists(unhandledFixed, unhandledAny); - activeLists = new RegisterBindingLists(Interval.EndMarker, Interval.EndMarker); - inactiveLists = new RegisterBindingLists(Interval.EndMarker, Interval.EndMarker); - currentPosition = -1; - current = null; - nextInterval(); - } - - void removeFromList(Interval interval) { - if (interval.state == State.Active) { - activeLists.remove(RegisterBinding.Any, interval); - } else { - assert interval.state == State.Inactive : "invalid state"; - inactiveLists.remove(RegisterBinding.Any, interval); - } - } - - void walkTo(State state, int from) { - assert state == State.Active || state == State.Inactive : "wrong state"; - for (RegisterBinding binding : RegisterBinding.VALUES) { - Interval prevprev = null; - Interval prev = (state == State.Active) ? activeLists.get(binding) : inactiveLists.get(binding); - Interval next = prev; - while (next.currentFrom() <= from) { - Interval cur = next; - next = cur.next; - - boolean rangeHasChanged = false; - while (cur.currentTo() <= from) { - cur.nextRange(); - rangeHasChanged = true; - } - - // also handle move from inactive list to active list - rangeHasChanged = rangeHasChanged || (state == State.Inactive && cur.currentFrom() <= from); - - if (rangeHasChanged) { - // remove cur from list - if (prevprev == null) { - if (state == State.Active) { - activeLists.set(binding, next); - } else { - inactiveLists.set(binding, next); - } - } else { - prevprev.next = next; - } - prev = next; - if (cur.currentAtEnd()) { - // move to handled state (not maintained as a list) - cur.state = State.Handled; - intervalMoved(cur, binding, state, State.Handled); - } else if (cur.currentFrom() <= from) { - // sort into active list - activeLists.addToListSortedByCurrentFromPositions(binding, cur); - cur.state = State.Active; - if (prev == cur) { - assert state == State.Active : "check"; - prevprev = prev; - prev = cur.next; - } - intervalMoved(cur, binding, state, State.Active); - } else { - // sort into inactive list - inactiveLists.addToListSortedByCurrentFromPositions(binding, cur); - cur.state = State.Inactive; - if (prev == cur) { - assert state == State.Inactive : "check"; - prevprev = prev; - prev = cur.next; - } - intervalMoved(cur, binding, state, State.Inactive); - } - } else { - prevprev = prev; - prev = cur.next; - } - } - } - } - - void nextInterval() { - RegisterBinding binding; - Interval any = unhandledLists.any; - Interval fixed = unhandledLists.fixed; - - if (any != Interval.EndMarker) { - // intervals may start at same position . prefer fixed interval - binding = fixed != Interval.EndMarker && fixed.from() <= any.from() ? RegisterBinding.Fixed : RegisterBinding.Any; - - assert binding == RegisterBinding.Fixed && fixed.from() <= any.from() || binding == RegisterBinding.Any && any.from() <= fixed.from() : "wrong interval!!!"; - assert any == Interval.EndMarker || fixed == Interval.EndMarker || any.from() != fixed.from() || binding == RegisterBinding.Fixed : "if fixed and any-Interval start at same position, fixed must be processed first"; - - } else if (fixed != Interval.EndMarker) { - binding = RegisterBinding.Fixed; - } else { - current = null; - return; - } - currentBinding = binding; - current = unhandledLists.get(binding); - unhandledLists.set(binding, current.next); - current.next = Interval.EndMarker; - current.rewindRange(); - } - - void walkTo(int toOpId) { - assert currentPosition <= toOpId : "can not walk backwards"; - while (current != null) { - boolean isActive = current.from() <= toOpId; - int opId = isActive ? current.from() : toOpId; - - if (C1XOptions.TraceLinearScanLevel >= 2 && !TTY.isSuppressed()) { - if (currentPosition < opId) { - TTY.println(); - TTY.println("walkTo(%d) *", opId); - } - } - - // set currentPosition prior to call of walkTo - currentPosition = opId; - - // call walkTo even if currentPosition == id - walkTo(State.Active, opId); - walkTo(State.Inactive, opId); - - if (isActive) { - current.state = State.Active; - if (activateCurrent()) { - activeLists.addToListSortedByCurrentFromPositions(currentBinding, current); - intervalMoved(current, currentBinding, State.Unhandled, State.Active); - } - - nextInterval(); - } else { - return; - } - } - } - - private void intervalMoved(Interval interval, RegisterBinding kind, State from, State to) { - // intervalMoved() is called whenever an interval moves from one interval list to another. - // In the implementation of this method it is prohibited to move the interval to any list. - if (C1XOptions.TraceLinearScanLevel >= 4 && !TTY.isSuppressed()) { - TTY.print(from.toString() + " to " + to.toString()); - TTY.fillTo(23); - TTY.out().println(interval.logString(allocator)); - } - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/alloc/LIRInsertionBuffer.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/alloc/LIRInsertionBuffer.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,136 +0,0 @@ -/* - * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.alloc; - -import java.util.*; - -import com.sun.c1x.lir.*; -import com.sun.c1x.util.*; -import com.sun.cri.ci.*; - -/** - * - * @author Thomas Wuerthinger - */ -public final class LIRInsertionBuffer { - - private LIRList lir; // the lir list where ops of this buffer should be inserted later (null when uninitialized) - - // list of insertion points. index and count are stored alternately: - // indexAndCount[i * 2]: the index into lir list where "count" ops should be inserted - // indexAndCount[i * 2 + 1]: the number of ops to be inserted at index - private final IntList indexAndCount; - - // the LIROps to be inserted - private final List ops; - - private void appendNew(int index, int count) { - indexAndCount.add(index); - indexAndCount.add(count); - } - - private void setCountAt(int i, int value) { - indexAndCount.set((i << 1) + 1, value); - } - - LIRInsertionBuffer() { - ops = new ArrayList(8); - indexAndCount = new IntList(8); - } - - // must be called before using the insertion buffer - void init(LIRList lir) { - assert !initialized() : "already initialized"; - this.lir = lir; - indexAndCount.clear(); - ops.clear(); - } - - boolean initialized() { - return lir != null; - } - - // called automatically when the buffer is appended to the LIRList - public void finish() { - lir = null; - } - - // accessors - public LIRList lirList() { - return lir; - } - - public int numberOfInsertionPoints() { - return indexAndCount.size() >> 1; - } - - public int indexAt(int i) { - return indexAndCount.get((i << 1)); - } - - public int countAt(int i) { - return indexAndCount.get((i << 1) + 1); - } - - public int numberOfOps() { - return ops.size(); - } - - public LIRInstruction opAt(int i) { - return ops.get(i); - } - - void move(int index, CiValue src, CiValue dst, LIRDebugInfo info) { - append(index, new LIROp1(LIROpcode.Move, src, dst, dst.kind, info)); - } - - // Implementation of LIRInsertionBuffer - - private void append(int index, LIRInstruction op) { - assert indexAndCount.size() % 2 == 0 : "must have a count for each index"; - - int i = numberOfInsertionPoints() - 1; - if (i < 0 || indexAt(i) < index) { - appendNew(index, 1); - } else { - assert indexAt(i) == index : "can append LIROps in ascending order only"; - assert countAt(i) > 0 : "check"; - setCountAt(i, countAt(i) + 1); - } - ops.add(op); - - assert verify(); - } - - private boolean verify() { - int sum = 0; - int prevIdx = -1; - - for (int i = 0; i < numberOfInsertionPoints(); i++) { - assert prevIdx < indexAt(i) : "index must be ordered ascending"; - sum += countAt(i); - } - assert sum == numberOfOps() : "wrong total sum"; - return true; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/alloc/LinearScan.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/alloc/LinearScan.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2317 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.alloc; - -import static com.sun.cri.ci.CiUtil.*; -import static java.lang.reflect.Modifier.*; - -import java.util.*; - -import com.oracle.graal.graph.*; -import com.sun.c1x.*; -import com.sun.c1x.alloc.Interval.*; -import com.sun.c1x.debug.*; -import com.sun.c1x.gen.*; -import com.sun.c1x.graph.*; -import com.sun.c1x.ir.*; -import com.sun.c1x.lir.*; -import com.sun.c1x.lir.LIRInstruction.*; -import com.sun.c1x.observer.*; -import com.sun.c1x.util.*; -import com.sun.c1x.value.*; -import com.sun.c1x.value.FrameState.*; -import com.sun.cri.ci.*; -import com.sun.cri.ri.*; - -/** - * An implementation of the linear scan register allocator algorithm described - * in "Optimized Interval Splitting in a Linear Scan Register Allocator" - * by Christian Wimmer and Hanspeter Moessenboeck. - * - * @author Christian Wimmer (original HotSpot implementation) - * @author Thomas Wuerthinger - * @author Doug Simon - */ -public final class LinearScan { - - final C1XCompilation compilation; - final IR ir; - final LIRGenerator gen; - final FrameMap frameMap; - final RiRegisterAttributes[] registerAttributes; - final CiRegister[] registers; - - private static final int INITIAL_SPLIT_INTERVALS_CAPACITY = 32; - - /** - * List of blocks in linear-scan order. This is only correct as long as the CFG does not change. - */ - final LIRBlock[] sortedBlocks; - - final OperandPool operands; - - /** - * Number of stack slots used for intervals allocated to memory. - */ - int maxSpills; - - /** - * Unused spill slot for a single-word value because of alignment of a double-word value. - */ - CiStackSlot unusedSpillSlot; - - /** - * Map from {@linkplain #operandNumber(CiValue) operand numbers} to intervals. - */ - Interval[] intervals; - - /** - * The number of valid entries in {@link #intervals}. - */ - int intervalsSize; - - /** - * The index of the first entry in {@link #intervals} for a {@linkplain #createDerivedInterval(Interval) derived interval}. - */ - int firstDerivedIntervalIndex = -1; - - /** - * Intervals sorted by {@link Interval#from()}. - */ - Interval[] sortedIntervals; - - /** - * Map from an instruction {@linkplain LIRInstruction#id id} to the instruction. - * Entries should be retrieved with {@link #instructionForId(int)} as the id is - * not simply an index into this array. - */ - LIRInstruction[] opIdToInstructionMap; - - /** - * Map from an instruction {@linkplain LIRInstruction#id id} to the {@linkplain - * LIRBlock block} containing the instruction. Entries should be retrieved with - * {@link #blockForId(int)} as the id is not simply an index into this array. - */ - LIRBlock[] opIdToBlockMap; - - /** - * Bit set for each variable that is contained in each loop. - */ - BitMap2D intervalInLoop; - - public LinearScan(C1XCompilation compilation, IR ir, LIRGenerator gen, FrameMap frameMap) { - this.compilation = compilation; - this.ir = ir; - this.gen = gen; - this.frameMap = frameMap; - this.maxSpills = frameMap.initialSpillSlot(); - this.unusedSpillSlot = null; - this.sortedBlocks = ir.linearScanOrder().toArray(new LIRBlock[ir.linearScanOrder().size()]); - CiRegister[] allocatableRegisters = compilation.registerConfig.getAllocatableRegisters(); - this.registers = new CiRegister[CiRegister.maxRegisterNumber(allocatableRegisters) + 1]; - for (CiRegister reg : allocatableRegisters) { - registers[reg.number] = reg; - } - this.registerAttributes = compilation.registerConfig.getAttributesMap(); - this.operands = gen.operands; - } - - /** - * Converts an operand (variable or register) to an index in a flat address space covering all the - * {@linkplain CiVariable variables} and {@linkplain CiRegisterValue registers} being processed by this - * allocator. - */ - int operandNumber(CiValue operand) { - return operands.operandNumber(operand); - } - - static final IntervalPredicate IS_PRECOLORED_INTERVAL = new IntervalPredicate() { - @Override - public boolean apply(Interval i) { - return i.operand.isRegister(); - } - }; - - static final IntervalPredicate IS_VARIABLE_INTERVAL = new IntervalPredicate() { - @Override - public boolean apply(Interval i) { - return i.operand.isVariable(); - } - }; - - static final IntervalPredicate IS_OOP_INTERVAL = new IntervalPredicate() { - @Override - public boolean apply(Interval i) { - return !i.operand.isRegister() && i.kind() == CiKind.Object; - } - }; - - /** - * Gets an object describing the attributes of a given register according to this register configuration. - */ - RiRegisterAttributes attributes(CiRegister reg) { - return registerAttributes[reg.number]; - } - - /** - * Allocates the next available spill slot for a value of a given kind. - */ - CiStackSlot allocateSpillSlot(CiKind kind) { - CiStackSlot spillSlot; - if (numberOfSpillSlots(kind) == 2) { - if (isOdd(maxSpills)) { - // alignment of double-slot values - // the hole because of the alignment is filled with the next single-slot value - assert unusedSpillSlot == null : "wasting a spill slot"; - unusedSpillSlot = CiStackSlot.get(kind, maxSpills); - maxSpills++; - } - spillSlot = CiStackSlot.get(kind, maxSpills); - maxSpills += 2; - } else if (unusedSpillSlot != null) { - // re-use hole that was the result of a previous double-word alignment - spillSlot = unusedSpillSlot; - unusedSpillSlot = null; - } else { - spillSlot = CiStackSlot.get(kind, maxSpills); - maxSpills++; - } - - return spillSlot; - } - - void assignSpillSlot(Interval interval) { - // assign the canonical spill slot of the parent (if a part of the interval - // is already spilled) or allocate a new spill slot - if (interval.spillSlot() != null) { - interval.assignLocation(interval.spillSlot()); - } else { - CiStackSlot slot = allocateSpillSlot(interval.kind()); - interval.setSpillSlot(slot); - interval.assignLocation(slot); - } - } - - /** - * Creates a new interval. - * - * @param operand the operand for the interval - * @return the created interval - */ - Interval createInterval(CiValue operand) { - assert isProcessed(operand); - assert operand.isLegal(); - int operandNumber = operandNumber(operand); - Interval interval = new Interval(operand, operandNumber); - assert operandNumber < intervalsSize; - assert intervals[operandNumber] == null; - intervals[operandNumber] = interval; - return interval; - } - - /** - * Creates an interval as a result of splitting or spilling another interval. - * - * @param source an interval being split of spilled - * @return a new interval derived from {@code source} - */ - Interval createDerivedInterval(Interval source) { - if (firstDerivedIntervalIndex == -1) { - firstDerivedIntervalIndex = intervalsSize; - } - if (intervalsSize == intervals.length) { - intervals = Arrays.copyOf(intervals, intervals.length * 2); - } - intervalsSize++; - Interval interval = createInterval(operands.newVariable(source.kind())); - assert intervals[intervalsSize - 1] == interval; - return interval; - } - - // copy the variable flags if an interval is split - void copyRegisterFlags(Interval from, Interval to) { - if (operands.mustBeByteRegister(from.operand)) { - operands.setMustBeByteRegister((CiVariable) to.operand); - } - - // Note: do not copy the mustStartInMemory flag because it is not necessary for child - // intervals (only the very beginning of the interval must be in memory) - } - - // access to block list (sorted in linear scan order) - int blockCount() { - assert sortedBlocks.length == ir.linearScanOrder().size() : "invalid cached block list"; - return sortedBlocks.length; - } - - LIRBlock blockAt(int index) { - assert sortedBlocks[index] == ir.linearScanOrder().get(index) : "invalid cached block list"; - return sortedBlocks[index]; - } - - /** - * Gets the size of the {@link LIRBlock#liveIn} and {@link LIRBlock#liveOut} sets for a basic block. These sets do - * not include any operands allocated as a result of creating {@linkplain #createDerivedInterval(Interval) derived - * intervals}. - */ - int liveSetSize() { - return firstDerivedIntervalIndex == -1 ? operands.size() : firstDerivedIntervalIndex; - } - - int numLoops() { - return ir.numLoops(); - } - - boolean isIntervalInLoop(int interval, int loop) { - return intervalInLoop.at(interval, loop); - } - - Interval intervalFor(CiValue operand) { - int operandNumber = operandNumber(operand); - assert operandNumber < intervalsSize; - return intervals[operandNumber]; - } - - /** - * Gets the highest instruction id allocated by this object. - */ - int maxOpId() { - assert opIdToInstructionMap.length > 0 : "no operations"; - return (opIdToInstructionMap.length - 1) << 1; - } - - /** - * Converts an {@linkplain LIRInstruction#id instruction id} to an instruction index. - * All LIR instructions in a method have an index one greater than their linear-scan order predecesor - * with the first instruction having an index of 0. - */ - static int opIdToIndex(int opId) { - return opId >> 1; - } - - /** - * Retrieves the {@link LIRInstruction} based on its {@linkplain LIRInstruction#id id}. - * - * @param opId an instruction {@linkplain LIRInstruction#id id} - * @return the instruction whose {@linkplain LIRInstruction#id} {@code == id} - */ - LIRInstruction instructionForId(int opId) { - assert isEven(opId) : "opId not even"; - LIRInstruction instr = opIdToInstructionMap[opIdToIndex(opId)]; - assert instr.id == opId; - return instr; - } - - /** - * Gets the block containing a given instruction. - * - * @param opId an instruction {@linkplain LIRInstruction#id id} - * @return the block containing the instruction denoted by {@code opId} - */ - LIRBlock blockForId(int opId) { - assert opIdToBlockMap.length > 0 && opId >= 0 && opId <= maxOpId() + 1 : "opId out of range"; - return opIdToBlockMap[opIdToIndex(opId)]; - } - - boolean isBlockBegin(int opId) { - return opId == 0 || blockForId(opId) != blockForId(opId - 1); - } - - boolean coversBlockBegin(int opId1, int opId2) { - return blockForId(opId1) != blockForId(opId2); - } - - /** - * Determines if an {@link LIRInstruction} destroys all caller saved registers. - * - * @param opId an instruction {@linkplain LIRInstruction#id id} - * @return {@code true} if the instruction denoted by {@code id} destroys all caller saved registers. - */ - boolean hasCall(int opId) { - assert isEven(opId) : "opId not even"; - return instructionForId(opId).hasCall; - } - - /** - * Eliminates moves from register to stack if the stack slot is known to be correct. - */ - void changeSpillDefinitionPos(Interval interval, int defPos) { - assert interval.isSplitParent() : "can only be called for split parents"; - - switch (interval.spillState()) { - case NoDefinitionFound: - assert interval.spillDefinitionPos() == -1 : "must no be set before"; - interval.setSpillDefinitionPos(defPos); - interval.setSpillState(SpillState.NoSpillStore); - break; - - case NoSpillStore: - assert defPos <= interval.spillDefinitionPos() : "positions are processed in reverse order when intervals are created"; - if (defPos < interval.spillDefinitionPos() - 2 || instructionForId(interval.spillDefinitionPos()).code == LIROpcode.Xir) { - // second definition found, so no spill optimization possible for this interval - interval.setSpillState(SpillState.NoOptimization); - } else { - // two consecutive definitions (because of two-operand LIR form) - assert blockForId(defPos) == blockForId(interval.spillDefinitionPos()) : "block must be equal"; - } - break; - - case NoOptimization: - // nothing to do - break; - - default: - throw new CiBailout("other states not allowed at this time"); - } - } - - // called during register allocation - void changeSpillState(Interval interval, int spillPos) { - switch (interval.spillState()) { - case NoSpillStore: { - int defLoopDepth = blockForId(interval.spillDefinitionPos()).loopDepth(); - int spillLoopDepth = blockForId(spillPos).loopDepth(); - - if (defLoopDepth < spillLoopDepth) { - // the loop depth of the spilling position is higher then the loop depth - // at the definition of the interval . move write to memory out of loop - // by storing at definitin of the interval - interval.setSpillState(SpillState.StoreAtDefinition); - } else { - // the interval is currently spilled only once, so for now there is no - // reason to store the interval at the definition - interval.setSpillState(SpillState.OneSpillStore); - } - break; - } - - case OneSpillStore: { - // the interval is spilled more then once, so it is better to store it to - // memory at the definition - interval.setSpillState(SpillState.StoreAtDefinition); - break; - } - - case StoreAtDefinition: - case StartInMemory: - case NoOptimization: - case NoDefinitionFound: - // nothing to do - break; - - default: - throw new CiBailout("other states not allowed at this time"); - } - } - - abstract static class IntervalPredicate { - abstract boolean apply(Interval i); - } - - private static final IntervalPredicate mustStoreAtDefinition = new IntervalPredicate() { - @Override - public boolean apply(Interval i) { - return i.isSplitParent() && i.spillState() == SpillState.StoreAtDefinition; - } - }; - - // called once before assignment of register numbers - void eliminateSpillMoves() { - if (C1XOptions.TraceLinearScanLevel >= 3) { - TTY.println(" Eliminating unnecessary spill moves"); - } - - // collect all intervals that must be stored after their definition. - // the list is sorted by Interval.spillDefinitionPos - Interval interval; - interval = createUnhandledLists(mustStoreAtDefinition, null).first; - if (C1XOptions.DetailedAsserts) { - checkIntervals(interval); - } - - LIRInsertionBuffer insertionBuffer = new LIRInsertionBuffer(); - int numBlocks = blockCount(); - for (int i = 0; i < numBlocks; i++) { - LIRBlock block = blockAt(i); - List instructions = block.lir().instructionsList(); - int numInst = instructions.size(); - boolean hasNew = false; - - // iterate all instructions of the block. skip the first because it is always a label - for (int j = 1; j < numInst; j++) { - LIRInstruction op = instructions.get(j); - int opId = op.id; - - if (opId == -1) { - CiValue resultOperand = op.result(); - // remove move from register to stack if the stack slot is guaranteed to be correct. - // only moves that have been inserted by LinearScan can be removed. - assert op.code == LIROpcode.Move : "only moves can have a opId of -1"; - assert resultOperand.isVariable() : "LinearScan inserts only moves to variables"; - - LIROp1 op1 = (LIROp1) op; - Interval curInterval = intervalFor(resultOperand); - - if (!curInterval.location().isRegister() && curInterval.alwaysInMemory()) { - // move target is a stack slot that is always correct, so eliminate instruction - if (C1XOptions.TraceLinearScanLevel >= 4) { - TTY.println("eliminating move from interval %d to %d", operandNumber(op1.operand()), operandNumber(op1.result())); - } - instructions.set(j, null); // null-instructions are deleted by assignRegNum - } - - } else { - // insert move from register to stack just after the beginning of the interval - assert interval == Interval.EndMarker || interval.spillDefinitionPos() >= opId : "invalid order"; - assert interval == Interval.EndMarker || (interval.isSplitParent() && interval.spillState() == SpillState.StoreAtDefinition) : "invalid interval"; - - while (interval != Interval.EndMarker && interval.spillDefinitionPos() == opId) { - if (!hasNew) { - // prepare insertion buffer (appended when all instructions of the block are processed) - insertionBuffer.init(block.lir()); - hasNew = true; - } - - CiValue fromLocation = interval.location(); - CiValue toLocation = canonicalSpillOpr(interval); - - assert fromLocation.isRegister() : "from operand must be a register but is: " + fromLocation + " toLocation=" + toLocation + " spillState=" + interval.spillState(); - assert toLocation.isStackSlot() : "to operand must be a stack slot"; - - insertionBuffer.move(j, fromLocation, toLocation, null); - - if (C1XOptions.TraceLinearScanLevel >= 4) { - CiStackSlot slot = interval.spillSlot(); - TTY.println("inserting move after definition of interval %d to stack slot %d%s at opId %d", - interval.operandNumber, slot.index(), slot.inCallerFrame() ? " in caller frame" : "", opId); - } - - interval = interval.next; - } - } - } // end of instruction iteration - - if (hasNew) { - block.lir().append(insertionBuffer); - } - } // end of block iteration - - assert interval == Interval.EndMarker : "missed an interval"; - } - - private void checkIntervals(Interval interval) { - Interval prev = null; - Interval temp = interval; - while (temp != Interval.EndMarker) { - assert temp.spillDefinitionPos() > 0 : "invalid spill definition pos"; - if (prev != null) { - assert temp.from() >= prev.from() : "intervals not sorted"; - assert temp.spillDefinitionPos() >= prev.spillDefinitionPos() : "when intervals are sorted by from : then they must also be sorted by spillDefinitionPos"; - } - - assert temp.spillSlot() != null : "interval has no spill slot assigned"; - assert temp.spillDefinitionPos() >= temp.from() : "invalid order"; - assert temp.spillDefinitionPos() <= temp.from() + 2 : "only intervals defined once at their start-pos can be optimized"; - - if (C1XOptions.TraceLinearScanLevel >= 4) { - TTY.println("interval %d (from %d to %d) must be stored at %d", temp.operandNumber, temp.from(), temp.to(), temp.spillDefinitionPos()); - } - - prev = temp; - temp = temp.next; - } - } - - /** - * Numbers all instructions in all blocks. The numbering follows the {@linkplain ComputeLinearScanOrder linear scan order}. - */ - void numberInstructions() { - // Assign IDs to LIR nodes and build a mapping, lirOps, from ID to LIRInstruction node. - int numBlocks = blockCount(); - int numInstructions = 0; - for (int i = 0; i < numBlocks; i++) { - numInstructions += blockAt(i).lir().instructionsList().size(); - } - - // initialize with correct length - opIdToInstructionMap = new LIRInstruction[numInstructions]; - opIdToBlockMap = new LIRBlock[numInstructions]; - - int opId = 0; - int index = 0; - - for (int i = 0; i < numBlocks; i++) { - LIRBlock block = blockAt(i); - block.setFirstLirInstructionId(opId); - List instructions = block.lir().instructionsList(); - - int numInst = instructions.size(); - for (int j = 0; j < numInst; j++) { - LIRInstruction op = instructions.get(j); - op.id = opId; - - opIdToInstructionMap[index] = op; - opIdToBlockMap[index] = block; - assert instructionForId(opId) == op : "must match"; - - index++; - opId += 2; // numbering of lirOps by two - } - block.setLastLirInstructionId((opId - 2)); - } - assert index == numInstructions : "must match"; - assert (index << 1) == opId : "must match: " + (index << 1); - } - - /** - * Computes local live sets (i.e. {@link LIRBlock#liveGen} and {@link LIRBlock#liveKill}) separately for each block. - */ - void computeLocalLiveSets() { - int numBlocks = blockCount(); - int liveSize = liveSetSize(); - - BitMap2D localIntervalInLoop = new BitMap2D(operands.size(), numLoops()); - - // iterate all blocks - for (int i = 0; i < numBlocks; i++) { - LIRBlock block = blockAt(i); - final CiBitMap liveGen = new CiBitMap(liveSize); - final CiBitMap liveKill = new CiBitMap(liveSize); - - List instructions = block.lir().instructionsList(); - int numInst = instructions.size(); - - // iterate all instructions of the block. skip the first because it is always a label - assert !instructions.get(0).hasOperands() : "first operation must always be a label"; - for (int j = 1; j < numInst; j++) { - final LIRInstruction op = instructions.get(j); - - // iterate input operands of instruction - int n = op.operandCount(LIRInstruction.OperandMode.Input); - for (int k = 0; k < n; k++) { - CiValue operand = op.operandAt(LIRInstruction.OperandMode.Input, k); - - if (operand.isVariable()) { - int operandNum = operandNumber(operand); - if (!liveKill.get(operandNum)) { - liveGen.set(operandNum); - if (C1XOptions.TraceLinearScanLevel >= 4) { - TTY.println(" Setting liveGen for operand %d at instruction %d", operandNum, op.id); - } - } - if (block.loopIndex() >= 0) { - localIntervalInLoop.setBit(operandNum, block.loopIndex()); - } - } - - if (C1XOptions.DetailedAsserts) { - assert operand.isVariableOrRegister() : "visitor should only return register operands"; - verifyInput(block, liveKill, operand); - } - } - - // Add uses of live locals from interpreter's point of view for proper debug information generation - LIRDebugInfo info = op.info; - if (info != null) { - info.state.forEachLiveStateValue(new ValueProcedure() { - public void doValue(Value value) { - CiValue operand = value.operand(); - if (operand.isVariable()) { - int operandNum = operandNumber(operand); - if (!liveKill.get(operandNum)) { - liveGen.set(operandNum); - if (C1XOptions.TraceLinearScanLevel >= 4) { - TTY.println(" Setting liveGen for value %s, LIR opId %d, operand %d because of state for " + op.toString(), Util.valueString(value), op.id, operandNum); - } - } - } else if (operand.isRegister()) { - assert !isProcessed(operand) && !operand.kind.isObject(); - } else { - assert operand.isConstant() || operand.isIllegal() : "invalid operand for deoptimization value: " + value; - } - } - }); - } - - // iterate temp operands of instruction - n = op.operandCount(LIRInstruction.OperandMode.Temp); - for (int k = 0; k < n; k++) { - CiValue operand = op.operandAt(LIRInstruction.OperandMode.Temp, k); - - if (operand.isVariable()) { - int varNum = operandNumber(operand); - liveKill.set(varNum); - if (block.loopIndex() >= 0) { - localIntervalInLoop.setBit(varNum, block.loopIndex()); - } - } - - if (C1XOptions.DetailedAsserts) { - assert operand.isVariableOrRegister() : "visitor should only return register operands"; - verifyTemp(liveKill, operand); - } - } - - // iterate output operands of instruction - n = op.operandCount(LIRInstruction.OperandMode.Output); - for (int k = 0; k < n; k++) { - CiValue operand = op.operandAt(LIRInstruction.OperandMode.Output, k); - - if (operand.isVariable()) { - int varNum = operandNumber(operand); - liveKill.set(varNum); - if (block.loopIndex() >= 0) { - localIntervalInLoop.setBit(varNum, block.loopIndex()); - } - } - - if (C1XOptions.DetailedAsserts) { - assert operand.isVariableOrRegister() : "visitor should only return register operands"; - // fixed intervals are never live at block boundaries, so - // they need not be processed in live sets - // process them only in debug mode so that this can be checked - verifyTemp(liveKill, operand); - } - } - } // end of instruction iteration - - block.liveGen = liveGen; - block.liveKill = liveKill; - block.liveIn = new CiBitMap(liveSize); - block.liveOut = new CiBitMap(liveSize); - - if (C1XOptions.TraceLinearScanLevel >= 4) { - TTY.println("liveGen B%d %s", block.blockID(), block.liveGen); - TTY.println("liveKill B%d %s", block.blockID(), block.liveKill); - } - } // end of block iteration - - intervalInLoop = localIntervalInLoop; - } - - private void verifyTemp(CiBitMap liveKill, CiValue operand) { - // fixed intervals are never live at block boundaries, so - // they need not be processed in live sets - // process them only in debug mode so that this can be checked - if (!operand.isVariable()) { - if (isProcessed(operand)) { - liveKill.set(operandNumber(operand)); - } - } - } - - private void verifyInput(LIRBlock block, CiBitMap liveKill, CiValue operand) { - // fixed intervals are never live at block boundaries, so - // they need not be processed in live sets. - // this is checked by these assertions to be sure about it. - // the entry block may have incoming - // values in registers, which is ok. - if (!operand.isVariable() && block != ir.startBlock) { - if (isProcessed(operand)) { - assert liveKill.get(operandNumber(operand)) : "using fixed register that is not defined in this block"; - } - } - } - - /** - * Performs a backward dataflow analysis to compute global live sets (i.e. {@link LIRBlock#liveIn} and - * {@link LIRBlock#liveOut}) for each block. - */ - void computeGlobalLiveSets() { - int numBlocks = blockCount(); - boolean changeOccurred; - boolean changeOccurredInBlock; - int iterationCount = 0; - CiBitMap liveOut = new CiBitMap(liveSetSize()); // scratch set for calculations - - // Perform a backward dataflow analysis to compute liveOut and liveIn for each block. - // The loop is executed until a fixpoint is reached (no changes in an iteration) - do { - changeOccurred = false; - - // iterate all blocks in reverse order - for (int i = numBlocks - 1; i >= 0; i--) { - LIRBlock block = blockAt(i); - - changeOccurredInBlock = false; - - // liveOut(block) is the union of liveIn(sux), for successors sux of block - int n = block.numberOfSux(); - if (n > 0) { - // block has successors - if (n > 0) { - liveOut.setFrom(block.suxAt(0).liveIn); - for (int j = 1; j < n; j++) { - liveOut.setUnion(block.suxAt(j).liveIn); - } - } else { - liveOut.clearAll(); - } - - if (!block.liveOut.isSame(liveOut)) { - // A change occurred. Swap the old and new live out sets to avoid copying. - CiBitMap temp = block.liveOut; - block.liveOut = liveOut; - liveOut = temp; - - changeOccurred = true; - changeOccurredInBlock = true; - } - } - - if (iterationCount == 0 || changeOccurredInBlock) { - // liveIn(block) is the union of liveGen(block) with (liveOut(block) & !liveKill(block)) - // note: liveIn has to be computed only in first iteration or if liveOut has changed! - CiBitMap liveIn = block.liveIn; - liveIn.setFrom(block.liveOut); - liveIn.setDifference(block.liveKill); - liveIn.setUnion(block.liveGen); - } - - if (C1XOptions.TraceLinearScanLevel >= 4) { - traceLiveness(changeOccurredInBlock, iterationCount, block); - } - } - iterationCount++; - - if (changeOccurred && iterationCount > 50) { - throw new CiBailout("too many iterations in computeGlobalLiveSets"); - } - } while (changeOccurred); - - if (C1XOptions.DetailedAsserts) { - verifyLiveness(numBlocks); - } - - // check that the liveIn set of the first block is empty - LIRBlock startBlock = ir.startBlock; - CiBitMap liveInArgs = new CiBitMap(startBlock.liveIn.size()); - if (!startBlock.liveIn.isSame(liveInArgs)) { - if (C1XOptions.DetailedAsserts) { - reportFailure(numBlocks); - } - - TTY.println("preds=" + startBlock.blockPredecessors().size() + ", succs=" + startBlock.blockSuccessors().size()); - TTY.println("startBlock-ID: " + startBlock.blockID()); - - // bailout of if this occurs in product mode. - throw new CiBailout("liveIn set of first block must be empty"); - } - } - - private void reportFailure(int numBlocks) { - TTY.println(compilation.method.toString()); - TTY.println("Error: liveIn set of first block must be empty (when this fails, variables are used before they are defined)"); - TTY.print("affected registers:"); - TTY.println(ir.startBlock.liveIn.toString()); - - // print some additional information to simplify debugging - for (int operandNum = 0; operandNum < ir.startBlock.liveIn.size(); operandNum++) { - if (ir.startBlock.liveIn.get(operandNum)) { - CiValue operand = operands.operandFor(operandNum); - Value instr = operand.isVariable() ? gen.operands.instructionForResult(((CiVariable) operand)) : null; - TTY.println(" var %d (HIR instruction %s)", operandNum, instr == null ? " " : instr.toString()); - - if (instr instanceof Phi) { - Phi phi = (Phi) instr; - TTY.println("phi block begin: " + phi.block()); - TTY.println("pred count on blockbegin: " + phi.block().predecessors().size()); - TTY.println("phi values: " + phi.valueCount()); - TTY.println("phi block preds:"); - for (Node n : phi.block().predecessors()) { - TTY.println(n.toString()); - } - } - - for (int j = 0; j < numBlocks; j++) { - LIRBlock block = blockAt(j); - if (block.liveGen.get(operandNum)) { - TTY.println(" used in block B%d", block.blockID()); - for (LIRInstruction ins : block.lir().instructionsList()) { - TTY.println(ins.id + ": " + ins.result() + " " + ins.toString()); - } - } - if (block.liveKill.get(operandNum)) { - TTY.println(" defined in block B%d", block.blockID()); - for (LIRInstruction ins : block.lir().instructionsList()) { - TTY.println(ins.id + ": " + ins.result() + " " + ins.toString()); - } - } - } - } - } - } - - private void verifyLiveness(int numBlocks) { - // check that fixed intervals are not live at block boundaries - // (live set must be empty at fixed intervals) - for (int i = 0; i < numBlocks; i++) { - LIRBlock block = blockAt(i); - for (int j = 0; j <= operands.maxRegisterNumber(); j++) { - assert !block.liveIn.get(j) : "liveIn set of fixed register must be empty"; - assert !block.liveOut.get(j) : "liveOut set of fixed register must be empty"; - assert !block.liveGen.get(j) : "liveGen set of fixed register must be empty"; - } - } - } - - private void traceLiveness(boolean changeOccurredInBlock, int iterationCount, LIRBlock block) { - char c = iterationCount == 0 || changeOccurredInBlock ? '*' : ' '; - TTY.print("(%d) liveIn%c B%d ", iterationCount, c, block.blockID()); - TTY.println(block.liveIn.toString()); - TTY.print("(%d) liveOut%c B%d ", iterationCount, c, block.blockID()); - TTY.println(block.liveOut.toString()); - } - - Interval addUse(CiValue operand, int from, int to, RegisterPriority registerPriority, CiKind kind) { - if (!isProcessed(operand)) { - return null; - } - if (C1XOptions.TraceLinearScanLevel >= 2 && kind == null) { - TTY.println(" use %s from %d to %d (%s)", operand, from, to, registerPriority.name()); - } - - if (kind == null) { - kind = operand.kind.stackKind(); - } - Interval interval = intervalFor(operand); - if (interval == null) { - interval = createInterval(operand); - } - - if (kind != CiKind.Illegal) { - interval.setKind(kind); - } - - if (operand.isVariable() && gen.operands.mustStayInMemory((CiVariable) operand)) { - interval.addRange(from, maxOpId()); - } else { - interval.addRange(from, to); - } - - interval.addUsePos(to, registerPriority); - return interval; - } - - void addTemp(CiValue operand, int tempPos, RegisterPriority registerPriority, CiKind kind) { - if (!isProcessed(operand)) { - return; - } - Interval interval = intervalFor(operand); - if (interval == null) { - interval = createInterval(operand); - } - - if (kind != CiKind.Illegal) { - interval.setKind(kind); - } - - interval.addRange(tempPos, tempPos + 1); - interval.addUsePos(tempPos, registerPriority); - } - - boolean isProcessed(CiValue operand) { - return !operand.isRegister() || attributes(operand.asRegister()).isAllocatable; - } - - void addDef(CiValue operand, int defPos, RegisterPriority registerPriority, CiKind kind) { - if (!isProcessed(operand)) { - return; - } - if (C1XOptions.TraceLinearScanLevel >= 2) { - TTY.println(" def %s defPos %d (%s)", operand, defPos, registerPriority.name()); - } - Interval interval = intervalFor(operand); - if (interval != null) { - - if (kind != CiKind.Illegal) { - interval.setKind(kind); - } - - Range r = interval.first(); - if (r.from <= defPos) { - // Update the starting point (when a range is first created for a use, its - // start is the beginning of the current block until a def is encountered.) - r.from = defPos; - interval.addUsePos(defPos, registerPriority); - - } else { - // Dead value - make vacuous interval - // also add register priority for dead intervals - interval.addRange(defPos, defPos + 1); - interval.addUsePos(defPos, registerPriority); - if (C1XOptions.TraceLinearScanLevel >= 2) { - TTY.println("Warning: def of operand %s at %d occurs without use", operand, defPos); - } - } - - } else { - // Dead value - make vacuous interval - // also add register priority for dead intervals - interval = createInterval(operand); - if (kind != CiKind.Illegal) { - interval.setKind(kind); - } - - interval.addRange(defPos, defPos + 1); - interval.addUsePos(defPos, registerPriority); - if (C1XOptions.TraceLinearScanLevel >= 2) { - TTY.println("Warning: dead value %s at %d in live intervals", operand, defPos); - } - } - - changeSpillDefinitionPos(interval, defPos); - if (registerPriority == RegisterPriority.None && interval.spillState().ordinal() <= SpillState.StartInMemory.ordinal()) { - // detection of method-parameters and roundfp-results - // TODO: move this directly to position where use-kind is computed - interval.setSpillState(SpillState.StartInMemory); - } - } - - /** - * Determines the register priority for an instruction's output/result operand. - */ - RegisterPriority registerPriorityOfOutputOperand(LIRInstruction op, CiValue operand) { - if (op.code == LIROpcode.Move) { - LIROp1 move = (LIROp1) op; - CiValue res = move.result(); - boolean resultInMemory = res.isVariable() && operands.mustStartInMemory((CiVariable) res); - - if (resultInMemory) { - // Begin of an interval with mustStartInMemory set. - // This interval will always get a stack slot first, so return noUse. - return RegisterPriority.None; - - } else if (move.operand().isStackSlot()) { - // method argument (condition must be equal to handleMethodArguments) - return RegisterPriority.None; - - } - } - - if (operand.isVariable() && operands.mustStartInMemory((CiVariable) operand)) { - // result is a stack-slot, so prevent immediate reloading - return RegisterPriority.None; - } - - // all other operands require a register - return RegisterPriority.MustHaveRegister; - } - - /** - * Determines the priority which with an instruction's input operand will be allocated a register. - */ - RegisterPriority registerPriorityOfInputOperand(LIRInstruction op, CiValue operand) { - if (op.code == LIROpcode.Move) { - LIROp1 move = (LIROp1) op; - CiValue res = move.result(); - boolean resultInMemory = res.isVariable() && operands.mustStartInMemory((CiVariable) res); - - if (resultInMemory) { - // Move to an interval with mustStartInMemory set. - // To avoid moves from stack to stack (not allowed) force the input operand to a register - return RegisterPriority.MustHaveRegister; - - } else if (move.operand().isVariableOrRegister() && move.result().isVariableOrRegister()) { - // The input operand is not forced to a register (moves from stack to register are allowed), - // but it is faster if the input operand is in a register - return RegisterPriority.ShouldHaveRegister; - } - } - - if (compilation.target.arch.isX86()) { - if (op.code == LIROpcode.Cmove) { - // conditional moves can handle stack operands - assert op.result().isVariableOrRegister(); - return RegisterPriority.ShouldHaveRegister; - } - - // optimizations for second input operand of arithmetic operations on Intel - // this operand is allowed to be on the stack in some cases - CiKind kind = operand.kind.stackKind(); - if (kind == CiKind.Float || kind == CiKind.Double) { - // SSE float instruction (CiKind.Double only supported with SSE2) - switch (op.code) { - case Cmp: - case Add: - case Sub: - case Mul: - case Div: { - LIROp2 op2 = (LIROp2) op; - if (op2.operand1() != op2.operand2() && op2.operand2() == operand) { - assert (op2.result().isVariableOrRegister() || op.code == LIROpcode.Cmp) && op2.operand1().isVariableOrRegister() : "cannot mark second operand as stack if others are not in register"; - return RegisterPriority.ShouldHaveRegister; - } - } - } - } else if (kind != CiKind.Long) { - // integer instruction (note: long operands must always be in register) - switch (op.code) { - case Cmp: - case Add: - case Sub: - case LogicAnd: - case LogicOr: - case LogicXor: { - LIROp2 op2 = (LIROp2) op; - if (op2.operand1() != op2.operand2() && op2.operand2() == operand) { - assert (op2.result().isVariableOrRegister() || op.code == LIROpcode.Cmp) && op2.operand1().isVariableOrRegister() : "cannot mark second operand as stack if others are not in register"; - return RegisterPriority.ShouldHaveRegister; - } - } - } - } - } // X86 - - // all other operands require a register - return RegisterPriority.MustHaveRegister; - } - - /** - * Optimizes moves related to incoming stack based arguments. - * The interval for the destination of such moves is assigned - * the stack slot (which is in the caller's frame) as its - * spill slot. - */ - void handleMethodArguments(LIRInstruction op) { - if (op.code == LIROpcode.Move) { - LIROp1 move = (LIROp1) op; - - if (move.operand().isStackSlot()) { - CiStackSlot slot = (CiStackSlot) move.operand(); - if (C1XOptions.DetailedAsserts) { - int argSlots = compilation.method.signature().argumentSlots(!isStatic(compilation.method.accessFlags())); - assert slot.index() >= 0 && slot.index() < argSlots; - assert move.id > 0 : "invalid id"; - assert blockForId(move.id).numberOfPreds() == 0 : "move from stack must be in first block"; - assert move.result().isVariable() : "result of move must be a variable"; - - if (C1XOptions.TraceLinearScanLevel >= 4) { - TTY.println("found move from stack slot %s to %s", slot, move.result()); - } - } - - Interval interval = intervalFor(move.result()); - CiStackSlot copySlot = slot; - if (C1XOptions.CopyPointerStackArguments && slot.kind == CiKind.Object) { - copySlot = allocateSpillSlot(slot.kind); - } - interval.setSpillSlot(copySlot); - interval.assignLocation(copySlot); - } - } - } - - void addRegisterHints(LIRInstruction op) { - switch (op.code) { - case Move: // fall through - case Convert: { - LIROp1 move = (LIROp1) op; - - CiValue moveFrom = move.operand(); - CiValue moveTo = move.result(); - - if (moveTo.isVariableOrRegister() && moveFrom.isVariableOrRegister()) { - Interval from = intervalFor(moveFrom); - Interval to = intervalFor(moveTo); - if (from != null && to != null) { - to.setLocationHint(from); - if (C1XOptions.TraceLinearScanLevel >= 4) { - TTY.println("operation at opId %d: added hint from interval %d to %d", move.id, from.operandNumber, to.operandNumber); - } - } - } - break; - } - case Cmove: { - LIROp2 cmove = (LIROp2) op; - - CiValue moveFrom = cmove.operand1(); - CiValue moveTo = cmove.result(); - - if (moveTo.isVariableOrRegister() && moveFrom.isVariableOrRegister()) { - Interval from = intervalFor(moveFrom); - Interval to = intervalFor(moveTo); - if (from != null && to != null) { - to.setLocationHint(from); - if (C1XOptions.TraceLinearScanLevel >= 4) { - TTY.println("operation at opId %d: added hint from interval %d to %d", cmove.id, from.operandNumber, to.operandNumber); - } - } - } - break; - } - } - } - - void buildIntervals() { - intervalsSize = operands.size(); - intervals = new Interval[intervalsSize + INITIAL_SPLIT_INTERVALS_CAPACITY]; - - // create a list with all caller-save registers (cpu, fpu, xmm) - RiRegisterConfig registerConfig = compilation.registerConfig; - CiRegister[] callerSaveRegs = registerConfig.getCallerSaveRegisters(); - - // iterate all blocks in reverse order - for (int i = blockCount() - 1; i >= 0; i--) { - LIRBlock block = blockAt(i); - List instructions = block.lir().instructionsList(); - final int blockFrom = block.firstLirInstructionId(); - int blockTo = block.lastLirInstructionId(); - - assert blockFrom == instructions.get(0).id; - assert blockTo == instructions.get(instructions.size() - 1).id; - - // Update intervals for operands live at the end of this block; - CiBitMap live = block.liveOut; - for (int operandNum = live.nextSetBit(0); operandNum >= 0; operandNum = live.nextSetBit(operandNum + 1)) { - assert live.get(operandNum) : "should not stop here otherwise"; - CiValue operand = operands.operandFor(operandNum); - if (C1XOptions.TraceLinearScanLevel >= 2) { - TTY.println("live in %s to %d", operand, blockTo + 2); - } - - addUse(operand, blockFrom, blockTo + 2, RegisterPriority.None, CiKind.Illegal); - - // add special use positions for loop-end blocks when the - // interval is used anywhere inside this loop. It's possible - // that the block was part of a non-natural loop, so it might - // have an invalid loop index. - if (block.isLinearScanLoopEnd() && block.loopIndex() != -1 && isIntervalInLoop(operandNum, block.loopIndex())) { - intervalFor(operand).addUsePos(blockTo + 1, RegisterPriority.LiveAtLoopEnd); - } - } - - // iterate all instructions of the block in reverse order. - // skip the first instruction because it is always a label - // definitions of intervals are processed before uses - assert !instructions.get(0).hasOperands() : "first operation must always be a label"; - for (int j = instructions.size() - 1; j >= 1; j--) { - LIRInstruction op = instructions.get(j); - final int opId = op.id; - - // add a temp range for each register if operation destroys caller-save registers - if (op.hasCall) { - for (CiRegister r : callerSaveRegs) { - if (attributes(r).isAllocatable) { - addTemp(r.asValue(), opId, RegisterPriority.None, CiKind.Illegal); - } - } - if (C1XOptions.TraceLinearScanLevel >= 4) { - TTY.println("operation destroys all caller-save registers"); - } - } - - // Add any platform dependent temps - pdAddTemps(op); - - // visit definitions (output and temp operands) - int k; - int n; - n = op.operandCount(LIRInstruction.OperandMode.Output); - for (k = 0; k < n; k++) { - CiValue operand = op.operandAt(LIRInstruction.OperandMode.Output, k); - assert operand.isVariableOrRegister(); - addDef(operand, opId, registerPriorityOfOutputOperand(op, operand), operand.kind.stackKind()); - } - - n = op.operandCount(LIRInstruction.OperandMode.Temp); - for (k = 0; k < n; k++) { - CiValue operand = op.operandAt(LIRInstruction.OperandMode.Temp, k); - assert operand.isVariableOrRegister(); - if (C1XOptions.TraceLinearScanLevel >= 2) { - TTY.println(" temp %s tempPos %d (%s)", operand, opId, RegisterPriority.MustHaveRegister.name()); - } - addTemp(operand, opId, RegisterPriority.MustHaveRegister, operand.kind.stackKind()); - } - - // visit uses (input operands) - n = op.operandCount(LIRInstruction.OperandMode.Input); - for (k = 0; k < n; k++) { - CiValue operand = op.operandAt(LIRInstruction.OperandMode.Input, k); - assert operand.isVariableOrRegister(); - RegisterPriority p = registerPriorityOfInputOperand(op, operand); - Interval interval = addUse(operand, blockFrom, opId, p, null); - if (interval != null && op instanceof LIRXirInstruction) { - Range range = interval.first(); - // (tw) Increase range by 1 in order to overlap the input with the temp and the output operand. - if (range.to == opId) { - range.to++; - } - } - } - - // Add uses of live locals from interpreter's point of view for proper - // debug information generation - // Treat these operands as temp values (if the live range is extended - // to a call site, the value would be in a register at the call otherwise) - LIRDebugInfo info = op.info; - if (info != null) { - info.state.forEachLiveStateValue(new ValueProcedure() { - public void doValue(Value value) { - CiValue operand = value.operand(); - if (operand.isVariableOrRegister()) { - addUse(operand, blockFrom, (opId + 1), RegisterPriority.None, null); - } - } - }); - } - - // special steps for some instructions (especially moves) - handleMethodArguments(op); - addRegisterHints(op); - - } // end of instruction iteration - } // end of block iteration - - // add the range [0, 1] to all fixed intervals. - // the register allocator need not handle unhandled fixed intervals - for (Interval interval : intervals) { - if (interval != null && interval.operand.isRegister()) { - interval.addRange(0, 1); - } - } - } - - // * Phase 5: actual register allocation - - private void pdAddTemps(LIRInstruction op) { - // TODO Platform dependent! - assert compilation.target.arch.isX86(); - - switch (op.code) { - case Tan: - case Sin: - case Cos: { - // The slow path for these functions may need to save and - // restore all live registers but we don't want to save and - // restore everything all the time, so mark the xmms as being - // killed. If the slow path were explicit or we could propagate - // live register masks down to the assembly we could do better - // but we don't have any easy way to do that right now. We - // could also consider not killing all xmm registers if we - // assume that slow paths are uncommon but it's not clear that - // would be a good idea. - if (C1XOptions.TraceLinearScanLevel >= 2) { - TTY.println("killing XMMs for trig"); - } - int opId = op.id; - - for (CiRegister r : compilation.registerConfig.getCallerSaveRegisters()) { - if (r.isFpu()) { - addTemp(r.asValue(), opId, RegisterPriority.None, CiKind.Illegal); - } - } - break; - } - } - - } - - boolean isSorted(Interval[] intervals) { - int from = -1; - for (Interval interval : intervals) { - assert interval != null; - assert from <= interval.from(); - from = interval.from(); - - // XXX: very slow! - assert Arrays.asList(this.intervals).contains(interval); - } - return true; - } - - Interval addToList(Interval first, Interval prev, Interval interval) { - Interval newFirst = first; - if (prev != null) { - prev.next = interval; - } else { - newFirst = interval; - } - return newFirst; - } - - Interval.Pair createUnhandledLists(IntervalPredicate isList1, IntervalPredicate isList2) { - assert isSorted(sortedIntervals) : "interval list is not sorted"; - - Interval list1 = Interval.EndMarker; - Interval list2 = Interval.EndMarker; - - Interval list1Prev = null; - Interval list2Prev = null; - Interval v; - - int n = sortedIntervals.length; - for (int i = 0; i < n; i++) { - v = sortedIntervals[i]; - if (v == null) { - continue; - } - - if (isList1.apply(v)) { - list1 = addToList(list1, list1Prev, v); - list1Prev = v; - } else if (isList2 == null || isList2.apply(v)) { - list2 = addToList(list2, list2Prev, v); - list2Prev = v; - } - } - - if (list1Prev != null) { - list1Prev.next = Interval.EndMarker; - } - if (list2Prev != null) { - list2Prev.next = Interval.EndMarker; - } - - assert list1Prev == null || list1Prev.next == Interval.EndMarker : "linear list ends not with sentinel"; - assert list2Prev == null || list2Prev.next == Interval.EndMarker : "linear list ends not with sentinel"; - - return new Interval.Pair(list1, list2); - } - - void sortIntervalsBeforeAllocation() { - int sortedLen = 0; - for (Interval interval : intervals) { - if (interval != null) { - sortedLen++; - } - } - - Interval[] sortedList = new Interval[sortedLen]; - int sortedIdx = 0; - int sortedFromMax = -1; - - // special sorting algorithm: the original interval-list is almost sorted, - // only some intervals are swapped. So this is much faster than a complete QuickSort - for (Interval interval : intervals) { - if (interval != null) { - int from = interval.from(); - - if (sortedFromMax <= from) { - sortedList[sortedIdx++] = interval; - sortedFromMax = interval.from(); - } else { - // the assumption that the intervals are already sorted failed, - // so this interval must be sorted in manually - int j; - for (j = sortedIdx - 1; j >= 0 && from < sortedList[j].from(); j--) { - sortedList[j + 1] = sortedList[j]; - } - sortedList[j + 1] = interval; - sortedIdx++; - } - } - } - sortedIntervals = sortedList; - } - - void sortIntervalsAfterAllocation() { - if (firstDerivedIntervalIndex == -1) { - // no intervals have been added during allocation, so sorted list is already up to date - return; - } - - Interval[] oldList = sortedIntervals; - Interval[] newList = Arrays.copyOfRange(intervals, firstDerivedIntervalIndex, intervalsSize); - int oldLen = oldList.length; - int newLen = newList.length; - - // conventional sort-algorithm for new intervals - Arrays.sort(newList, INTERVAL_COMPARATOR); - - // merge old and new list (both already sorted) into one combined list - Interval[] combinedList = new Interval[oldLen + newLen]; - int oldIdx = 0; - int newIdx = 0; - - while (oldIdx + newIdx < combinedList.length) { - if (newIdx >= newLen || (oldIdx < oldLen && oldList[oldIdx].from() <= newList[newIdx].from())) { - combinedList[oldIdx + newIdx] = oldList[oldIdx]; - oldIdx++; - } else { - combinedList[oldIdx + newIdx] = newList[newIdx]; - newIdx++; - } - } - - sortedIntervals = combinedList; - } - - private static final Comparator INTERVAL_COMPARATOR = new Comparator() { - - public int compare(Interval a, Interval b) { - if (a != null) { - if (b != null) { - return a.from() - b.from(); - } else { - return -1; - } - } else { - if (b != null) { - return 1; - } else { - return 0; - } - } - } - }; - - public void allocateRegisters() { - Interval precoloredIntervals; - Interval notPrecoloredIntervals; - - Interval.Pair result = createUnhandledLists(IS_PRECOLORED_INTERVAL, IS_VARIABLE_INTERVAL); - precoloredIntervals = result.first; - notPrecoloredIntervals = result.second; - - // allocate cpu registers - LinearScanWalker lsw = new LinearScanWalker(this, precoloredIntervals, notPrecoloredIntervals); - lsw.walk(); - lsw.finishAllocation(); - } - - // * Phase 6: resolve data flow - // (insert moves at edges between blocks if intervals have been split) - - // wrapper for Interval.splitChildAtOpId that performs a bailout in product mode - // instead of returning null - Interval splitChildAtOpId(Interval interval, int opId, LIRInstruction.OperandMode mode) { - Interval result = interval.getSplitChildAtOpId(opId, mode, this); - - if (result != null) { - if (C1XOptions.TraceLinearScanLevel >= 4) { - TTY.println("Split child at pos " + opId + " of interval " + interval.toString() + " is " + result.toString()); - } - return result; - } - - throw new CiBailout("LinearScan: interval is null"); - } - - Interval intervalAtBlockBegin(LIRBlock block, CiValue operand) { - assert operand.isVariable() : "register number out of bounds"; - assert intervalFor(operand) != null : "no interval found"; - - return splitChildAtOpId(intervalFor(operand), block.firstLirInstructionId(), LIRInstruction.OperandMode.Output); - } - - Interval intervalAtBlockEnd(LIRBlock block, CiValue operand) { - assert operand.isVariable() : "register number out of bounds"; - assert intervalFor(operand) != null : "no interval found"; - - return splitChildAtOpId(intervalFor(operand), block.lastLirInstructionId() + 1, LIRInstruction.OperandMode.Output); - } - - Interval intervalAtOpId(CiValue operand, int opId) { - assert operand.isVariable() : "register number out of bounds"; - assert intervalFor(operand) != null : "no interval found"; - - return splitChildAtOpId(intervalFor(operand), opId, LIRInstruction.OperandMode.Input); - } - - void resolveCollectMappings(LIRBlock fromBlock, LIRBlock toBlock, MoveResolver moveResolver) { - assert moveResolver.checkEmpty(); - - int numOperands = operands.size(); - CiBitMap liveAtEdge = toBlock.liveIn; - - // visit all variables for which the liveAtEdge bit is set - for (int operandNum = liveAtEdge.nextSetBit(0); operandNum >= 0; operandNum = liveAtEdge.nextSetBit(operandNum + 1)) { - assert operandNum < numOperands : "live information set for not exisiting interval"; - assert fromBlock.liveOut.get(operandNum) && toBlock.liveIn.get(operandNum) : "interval not live at this edge"; - - CiValue liveOperand = operands.operandFor(operandNum); - Interval fromInterval = intervalAtBlockEnd(fromBlock, liveOperand); - Interval toInterval = intervalAtBlockBegin(toBlock, liveOperand); - - if (fromInterval != toInterval && (fromInterval.location() != toInterval.location())) { - // need to insert move instruction - moveResolver.addMapping(fromInterval, toInterval); - } - } - } - - void resolveFindInsertPos(LIRBlock fromBlock, LIRBlock toBlock, MoveResolver moveResolver) { - if (fromBlock.numberOfSux() <= 1) { - if (C1XOptions.TraceLinearScanLevel >= 4) { - TTY.println("inserting moves at end of fromBlock B%d", fromBlock.blockID()); - } - - List instructions = fromBlock.lir().instructionsList(); - LIRInstruction instr = instructions.get(instructions.size() - 1); - if (instr instanceof LIRBranch) { - LIRBranch branch = (LIRBranch) instr; - // insert moves before branch - assert branch.cond() == Condition.TRUE : "block does not end with an unconditional jump"; - moveResolver.setInsertPosition(fromBlock.lir(), instructions.size() - 2); - } else { - moveResolver.setInsertPosition(fromBlock.lir(), instructions.size() - 1); - } - - } else { - if (C1XOptions.TraceLinearScanLevel >= 4) { - TTY.println("inserting moves at beginning of toBlock B%d", toBlock.blockID()); - } - - if (C1XOptions.DetailedAsserts) { - assert fromBlock.lir().instructionsList().get(0) instanceof LIRLabel : "block does not start with a label"; - - // because the number of predecessor edges matches the number of - // successor edges, blocks which are reached by switch statements - // may have be more than one predecessor but it will be guaranteed - // that all predecessors will be the same. - for (int i = 0; i < toBlock.numberOfPreds(); i++) { - assert fromBlock == toBlock.predAt(i) : "all critical edges must be broken"; - } - } - - moveResolver.setInsertPosition(toBlock.lir(), 0); - } - } - - /** - * Inserts necessary moves (spilling or reloading) at edges between blocks for intervals that - * have been split. - */ - void resolveDataFlow() { - int numBlocks = blockCount(); - MoveResolver moveResolver = new MoveResolver(this); - CiBitMap blockCompleted = new CiBitMap(numBlocks); - CiBitMap alreadyResolved = new CiBitMap(numBlocks); - - int i; - for (i = 0; i < numBlocks; i++) { - LIRBlock block = blockAt(i); - - // check if block has only one predecessor and only one successor - if (block.numberOfPreds() == 1 && block.numberOfSux() == 1) { - List instructions = block.lir().instructionsList(); - assert instructions.get(0).code == LIROpcode.Label : "block must start with label"; - assert instructions.get(instructions.size() - 1).code == LIROpcode.Branch : "block with successors must end with branch (" + block + "), " + instructions.get(instructions.size() - 1); - assert ((LIRBranch) instructions.get(instructions.size() - 1)).cond() == Condition.TRUE : "block with successor must end with unconditional branch"; - - // check if block is empty (only label and branch) - if (instructions.size() == 2) { - LIRBlock pred = block.predAt(0); - LIRBlock sux = block.suxAt(0); - - // prevent optimization of two consecutive blocks - if (!blockCompleted.get(pred.linearScanNumber()) && !blockCompleted.get(sux.linearScanNumber())) { - if (C1XOptions.TraceLinearScanLevel >= 3) { - TTY.println(" optimizing empty block B%d (pred: B%d, sux: B%d)", block.blockID(), pred.blockID(), sux.blockID()); - } - blockCompleted.set(block.linearScanNumber()); - - // directly resolve between pred and sux (without looking at the empty block between) - resolveCollectMappings(pred, sux, moveResolver); - if (moveResolver.hasMappings()) { - moveResolver.setInsertPosition(block.lir(), 0); - moveResolver.resolveAndAppendMoves(); - } - } - } - } - } - - for (i = 0; i < numBlocks; i++) { - if (!blockCompleted.get(i)) { - LIRBlock fromBlock = blockAt(i); - alreadyResolved.setFrom(blockCompleted); - - int numSux = fromBlock.numberOfSux(); - for (int s = 0; s < numSux; s++) { - LIRBlock toBlock = fromBlock.suxAt(s); - - // check for duplicate edges between the same blocks (can happen with switch blocks) - if (!alreadyResolved.get(toBlock.linearScanNumber())) { - if (C1XOptions.TraceLinearScanLevel >= 3) { - TTY.println(" processing edge between B%d and B%d", fromBlock.blockID(), toBlock.blockID()); - } - alreadyResolved.set(toBlock.linearScanNumber()); - - // collect all intervals that have been split between fromBlock and toBlock - resolveCollectMappings(fromBlock, toBlock, moveResolver); - if (moveResolver.hasMappings()) { - resolveFindInsertPos(fromBlock, toBlock, moveResolver); - moveResolver.resolveAndAppendMoves(); - } - } - } - } - } - } - - // * Phase 7: assign register numbers back to LIR - // (includes computation of debug information and oop maps) - - boolean verifyAssignedLocation(Interval interval, CiValue location) { - CiKind kind = interval.kind(); - - assert location.isRegister() || location.isStackSlot(); - - if (location.isRegister()) { - CiRegister reg = location.asRegister(); - - // register - switch (kind) { - case Byte: - case Char: - case Short: - case Jsr: - case Word: - case Object: - case Int: { - assert reg.isCpu() : "not cpu register"; - break; - } - - case Long: { - assert reg.isCpu() : "not cpu register"; - break; - } - - case Float: { - assert !compilation.target.arch.isX86() || reg.isFpu() : "not xmm register: " + reg; - break; - } - - case Double: { - assert !compilation.target.arch.isX86() || reg.isFpu() : "not xmm register: " + reg; - break; - } - - default: { - throw Util.shouldNotReachHere(); - } - } - } - return true; - } - - CiStackSlot canonicalSpillOpr(Interval interval) { - assert interval.spillSlot() != null : "canonical spill slot not set"; - return interval.spillSlot(); - } - - /** - * Assigns the allocated location for an LIR instruction operand back into the instruction. - * - * @param operand an LIR instruction operand - * @param opId the id of the LIR instruction using {@code operand} - * @param mode the usage mode for {@code operand} by the instruction - * @return the location assigned for the operand - */ - private CiValue colorLirOperand(CiVariable operand, int opId, OperandMode mode) { - Interval interval = intervalFor(operand); - assert interval != null : "interval must exist"; - - if (opId != -1) { - if (C1XOptions.DetailedAsserts) { - LIRBlock block = blockForId(opId); - if (block.numberOfSux() <= 1 && opId == block.lastLirInstructionId()) { - // check if spill moves could have been appended at the end of this block, but - // before the branch instruction. So the split child information for this branch would - // be incorrect. - LIRInstruction instr = block.lir().instructionsList().get(block.lir().instructionsList().size() - 1); - if (instr instanceof LIRBranch) { - LIRBranch branch = (LIRBranch) instr; - if (block.liveOut.get(operandNumber(operand))) { - assert branch.cond() == Condition.TRUE : "block does not end with an unconditional jump"; - throw new CiBailout("can't get split child for the last branch of a block because the information would be incorrect (moves are inserted before the branch in resolveDataFlow)"); - } - } - } - } - - // operands are not changed when an interval is split during allocation, - // so search the right interval here - interval = splitChildAtOpId(interval, opId, mode); - } - - return interval.location(); - } - - IntervalWalker initComputeOopMaps() { - // setup lists of potential oops for walking - Interval oopIntervals; - Interval nonOopIntervals; - - oopIntervals = createUnhandledLists(IS_OOP_INTERVAL, null).first; - - // intervals that have no oops inside need not to be processed. - // to ensure a walking until the last instruction id, add a dummy interval - // with a high operation id - nonOopIntervals = new Interval(CiValue.IllegalValue, -1); - nonOopIntervals.addRange(Integer.MAX_VALUE - 2, Integer.MAX_VALUE - 1); - - return new IntervalWalker(this, oopIntervals, nonOopIntervals); - } - - void computeOopMap(IntervalWalker iw, LIRInstruction op, LIRDebugInfo info, boolean isCallSite, CiBitMap frameRefMap, CiBitMap regRefMap) { - if (C1XOptions.TraceLinearScanLevel >= 3) { - TTY.println("creating oop map at opId %d", op.id); - } - - // walk before the current operation . intervals that start at - // the operation (i.e. output operands of the operation) are not - // included in the oop map - iw.walkBefore(op.id); - - // Iterate through active intervals - for (Interval interval = iw.activeLists.get(RegisterBinding.Fixed); interval != Interval.EndMarker; interval = interval.next) { - CiValue operand = interval.operand; - - assert interval.currentFrom() <= op.id && op.id <= interval.currentTo() : "interval should not be active otherwise"; - assert interval.operand.isVariable() : "fixed interval found"; - - // Check if this range covers the instruction. Intervals that - // start or end at the current operation are not included in the - // oop map, except in the case of patching moves. For patching - // moves, any intervals which end at this instruction are included - // in the oop map since we may safepoint while doing the patch - // before we've consumed the inputs. - if (op.id < interval.currentTo()) { - // caller-save registers must not be included into oop-maps at calls - assert !isCallSite || !operand.isRegister() || !isCallerSave(operand) : "interval is in a caller-save register at a call . register will be overwritten"; - - CiValue location = interval.location(); - if (location.isStackSlot()) { - location = frameMap.toStackAddress((CiStackSlot) location); - } - info.setOop(location, compilation, frameRefMap, regRefMap); - - // Spill optimization: when the stack value is guaranteed to be always correct, - // then it must be added to the oop map even if the interval is currently in a register - if (interval.alwaysInMemory() && op.id > interval.spillDefinitionPos() && !interval.location().equals(interval.spillSlot())) { - assert interval.spillDefinitionPos() > 0 : "position not set correctly"; - assert interval.spillSlot() != null : "no spill slot assigned"; - assert !interval.operand.isRegister() : "interval is on stack : so stack slot is registered twice"; - info.setOop(frameMap.toStackAddress(interval.spillSlot()), compilation, frameRefMap, regRefMap); - } - } - } - } - - private boolean isCallerSave(CiValue operand) { - return attributes(operand.asRegister()).isCallerSave; - } - - void computeOopMap(IntervalWalker iw, LIRInstruction op, LIRDebugInfo info, CiBitMap frameRefMap, CiBitMap regRefMap) { - computeOopMap(iw, op, info, op.hasCall, frameRefMap, regRefMap); - if (op instanceof LIRCall) { - List pointerSlots = ((LIRCall) op).pointerSlots; - if (pointerSlots != null) { - for (CiValue v : pointerSlots) { - info.setOop(v, compilation, frameRefMap, regRefMap); - } - } - } else if (op instanceof LIRXirInstruction) { - List pointerSlots = ((LIRXirInstruction) op).pointerSlots; - if (pointerSlots != null) { - for (CiValue v : pointerSlots) { - info.setOop(v, compilation, frameRefMap, regRefMap); - } - } - } - } - - CiValue toCiValue(int opId, Value value) { - if (value != null && value.operand() != CiValue.IllegalValue) { - CiValue operand = value.operand(); - Constant con = null; - if (value instanceof Constant) { - con = (Constant) value; - } - - assert con == null || operand.isVariable() || operand.isConstant() || operand.isIllegal() : "Constant instructions have only constant operands (or illegal if constant is optimized away)"; - - if (operand.isVariable()) { - OperandMode mode = OperandMode.Input; - LIRBlock block = blockForId(opId); - if (block.numberOfSux() == 1 && opId == block.lastLirInstructionId()) { - // generating debug information for the last instruction of a block. - // if this instruction is a branch, spill moves are inserted before this branch - // and so the wrong operand would be returned (spill moves at block boundaries are not - // considered in the live ranges of intervals) - // Solution: use the first opId of the branch target block instead. - final LIRInstruction instr = block.lir().instructionsList().get(block.lir().instructionsList().size() - 1); - if (instr instanceof LIRBranch) { - if (block.liveOut.get(operandNumber(operand))) { - opId = block.suxAt(0).firstLirInstructionId(); - mode = OperandMode.Output; - } - } - } - - // Get current location of operand - // The operand must be live because debug information is considered when building the intervals - // if the interval is not live, colorLirOperand will cause an assert on failure - operand = colorLirOperand((CiVariable) operand, opId, mode); - assert !hasCall(opId) || operand.isStackSlot() || !isCallerSave(operand) : "cannot have caller-save register operands at calls"; - return operand; - } else if (operand.isRegister()) { - assert false : "must not reach here"; - return operand; - } else { - assert value instanceof Constant; - assert operand.isConstant() : "operand must be constant"; - return operand; - } - } else { - // return a dummy value because real value not needed - return CiValue.IllegalValue; - } - } - - CiFrame computeFrameForState(FrameState state, int opId, CiBitMap frameRefMap) { - CiValue[] values = new CiValue[state.valuesSize() + state.locksSize()]; - int valueIndex = 0; - - for (int i = 0; i < state.valuesSize(); i++) { - values[valueIndex++] = toCiValue(opId, state.valueAt(i)); - } - - for (int i = 0; i < state.locksSize(); i++) { - if (compilation.runtime.sizeOfBasicObjectLock() != 0) { - CiStackSlot monitorAddress = frameMap.toMonitorBaseStackAddress(i); - values[valueIndex++] = monitorAddress; - assert frameRefMap != null; - CiStackSlot objectAddress = frameMap.toMonitorObjectStackAddress(i); -// LIRDebugInfo.setBit(frameRefMap, objectAddress.index()); - frameRefMap.set(objectAddress.index()); - } else { - Value lock = state.lockAt(i); - if (lock.isConstant() && compilation.runtime.asJavaClass(lock.asConstant()) != null) { - // lock on class for synchronized static method - values[valueIndex++] = lock.asConstant(); - } else { - values[valueIndex++] = toCiValue(opId, lock); - } - } - } - CiFrame caller = null; - if (state.outerFrameState() != null) { - caller = computeFrameForState(state.outerFrameState(), opId, frameRefMap); - } - return new CiFrame(caller, state.method, state.bci, values, state.localsSize(), state.stackSize(), state.locksSize()); - } - - private void computeDebugInfo(IntervalWalker iw, LIRInstruction op) { - assert iw != null : "interval walker needed for debug information"; - computeDebugInfo(iw, op, op.info); - - if (op instanceof LIRXirInstruction) { - LIRXirInstruction xir = (LIRXirInstruction) op; - if (xir.infoAfter != null) { - computeDebugInfo(iw, op, xir.infoAfter); - } - } - } - - - private void computeDebugInfo(IntervalWalker iw, LIRInstruction op, LIRDebugInfo info) { - if (info != null) { - if (info.debugInfo == null) { - int frameSize = compilation.frameMap().frameSize(); - int frameWords = frameSize / compilation.target.spillSlotSize; - CiBitMap frameRefMap = new CiBitMap(frameWords); - CiBitMap regRefMap = !op.hasCall ? new CiBitMap(compilation.target.arch.registerReferenceMapBitCount) : null; - CiFrame frame = compilation.placeholderState != null ? null : computeFrame(info.state, op.id, frameRefMap); - computeOopMap(iw, op, info, frameRefMap, regRefMap); - info.debugInfo = new CiDebugInfo(frame, regRefMap, frameRefMap); - } else if (C1XOptions.DetailedAsserts) { - assert info.debugInfo.frame().equals(computeFrame(info.state, op.id, new CiBitMap(info.debugInfo.frameRefMap.size()))); - } - } - } - - CiFrame computeFrame(FrameState state, int opId, CiBitMap frameRefMap) { - if (C1XOptions.TraceLinearScanLevel >= 3) { - TTY.println("creating debug information at opId %d", opId); - } - return computeFrameForState(state, opId, frameRefMap); - } - - private void assignLocations(List instructions, IntervalWalker iw) { - int numInst = instructions.size(); - boolean hasDead = false; - - for (int j = 0; j < numInst; j++) { - LIRInstruction op = instructions.get(j); - if (op == null) { // this can happen when spill-moves are removed in eliminateSpillMoves - hasDead = true; - continue; - } - - // iterate all modes of the visitor and process all virtual operands - for (LIRInstruction.OperandMode mode : LIRInstruction.OPERAND_MODES) { - int n = op.operandCount(mode); - for (int k = 0; k < n; k++) { - CiValue operand = op.operandAt(mode, k); - if (operand.isVariable()) { - op.setOperandAt(mode, k, colorLirOperand((CiVariable) operand, op.id, mode)); - } - } - } - - if (op.info != null) { - // compute reference map and debug information - computeDebugInfo(iw, op); - } - - // make sure we haven't made the op invalid. - assert op.verify(); - - // remove useless moves - if (op.code == LIROpcode.Move) { - CiValue src = op.operand(0); - CiValue dst = op.result(); - if (dst == src || src.equals(dst)) { - // TODO: what about o.f = o.f and exceptions? - instructions.set(j, null); - hasDead = true; - } - } - } - - if (hasDead) { - // iterate all instructions of the block and remove all null-values. - int insertPoint = 0; - for (int j = 0; j < numInst; j++) { - LIRInstruction op = instructions.get(j); - if (op != null) { - if (insertPoint != j) { - instructions.set(insertPoint, op); - } - insertPoint++; - } - } - Util.truncate(instructions, insertPoint); - } - } - - private void assignLocations() { - IntervalWalker iw = initComputeOopMaps(); - for (LIRBlock block : sortedBlocks) { - assignLocations(block.lir().instructionsList(), iw); - } - } - - public void allocate() { - if (C1XOptions.PrintTimers) { - C1XTimers.LIFETIME_ANALYSIS.start(); - } - - numberInstructions(); - - printLir("Before register allocation", true); - - computeLocalLiveSets(); - computeGlobalLiveSets(); - - buildIntervals(); - sortIntervalsBeforeAllocation(); - - if (C1XOptions.PrintTimers) { - C1XTimers.LIFETIME_ANALYSIS.stop(); - C1XTimers.LINEAR_SCAN.start(); - } - - printIntervals("Before register allocation"); - - allocateRegisters(); - - if (C1XOptions.PrintTimers) { - C1XTimers.LINEAR_SCAN.stop(); - C1XTimers.RESOLUTION.start(); - } - - resolveDataFlow(); - - if (C1XOptions.PrintTimers) { - C1XTimers.RESOLUTION.stop(); - C1XTimers.DEBUG_INFO.start(); - } - - C1XMetrics.LSRASpills += (maxSpills - frameMap.initialSpillSlot()); - - // fill in number of spill slots into frameMap - frameMap.finalizeFrame(maxSpills); - - printIntervals("After register allocation"); - printLir("After register allocation", true); - - sortIntervalsAfterAllocation(); - - if (C1XOptions.DetailedAsserts) { - verify(); - } - - eliminateSpillMoves(); - assignLocations(); - - if (C1XOptions.DetailedAsserts) { - verifyIntervals(); - } - - if (C1XOptions.PrintTimers) { - C1XTimers.DEBUG_INFO.stop(); - C1XTimers.CODE_CREATE.start(); - } - - printLir("After register number assignment", true); - EdgeMoveOptimizer.optimize(ir.linearScanOrder()); - ControlFlowOptimizer.optimize(ir); - printLir("After control flow optimization", false); - } - - void printIntervals(String label) { - if (C1XOptions.TraceLinearScanLevel >= 1) { - int i; - TTY.println(); - TTY.println(label); - - for (Interval interval : intervals) { - if (interval != null) { - TTY.out().println(interval.logString(this)); - } - } - - TTY.println(); - TTY.println("--- Basic Blocks ---"); - for (i = 0; i < blockCount(); i++) { - LIRBlock block = blockAt(i); - TTY.print("B%d [%d, %d, %d, %d] ", block.blockID(), block.firstLirInstructionId(), block.lastLirInstructionId(), block.loopIndex(), block.loopDepth()); - } - TTY.println(); - TTY.println(); - } - - if (compilation.compiler.isObserved()) { - compilation.compiler.fireCompilationEvent(new CompilationEvent(compilation, label, this, intervals, intervalsSize)); - } - } - - void printLir(String label, boolean hirValid) { - if (C1XOptions.TraceLinearScanLevel >= 1 && !TTY.isSuppressed()) { - TTY.println(); - TTY.println(label); - LIRList.printLIR(ir.linearScanOrder()); - TTY.println(); - } - - if (compilation.compiler.isObserved()) { - compilation.compiler.fireCompilationEvent(new CompilationEvent(compilation, label, compilation.graph, hirValid, true)); - } - } - - boolean verify() { - // (check that all intervals have a correct register and that no registers are overwritten) - if (C1XOptions.TraceLinearScanLevel >= 2) { - TTY.println(" verifying intervals *"); - } - verifyIntervals(); - - if (C1XOptions.TraceLinearScanLevel >= 2) { - TTY.println(" verifying that no oops are in fixed intervals *"); - } - //verifyNoOopsInFixedIntervals(); - - if (C1XOptions.TraceLinearScanLevel >= 2) { - TTY.println(" verifying that unpinned constants are not alive across block boundaries"); - } - verifyConstants(); - - if (C1XOptions.TraceLinearScanLevel >= 2) { - TTY.println(" verifying register allocation *"); - } - verifyRegisters(); - - if (C1XOptions.TraceLinearScanLevel >= 2) { - TTY.println(" no errors found *"); - } - - return true; - } - - private void verifyRegisters() { - RegisterVerifier verifier = new RegisterVerifier(this); - verifier.verify(blockAt(0)); - } - - void verifyIntervals() { - int len = intervalsSize; - - for (int i = 0; i < len; i++) { - Interval i1 = intervals[i]; - if (i1 == null) { - continue; - } - - i1.checkSplitChildren(); - - if (i1.operandNumber != i) { - TTY.println("Interval %d is on position %d in list", i1.operandNumber, i); - TTY.println(i1.logString(this)); - throw new CiBailout(""); - } - - if (i1.operand.isVariable() && i1.kind() == CiKind.Illegal) { - TTY.println("Interval %d has no type assigned", i1.operandNumber); - TTY.println(i1.logString(this)); - throw new CiBailout(""); - } - - if (i1.location() == null) { - TTY.println("Interval %d has no register assigned", i1.operandNumber); - TTY.println(i1.logString(this)); - throw new CiBailout(""); - } - - if (!isProcessed(i1.location())) { - TTY.println("Can not have an Interval for an ignored register " + i1.location()); - TTY.println(i1.logString(this)); - throw new CiBailout(""); - } - - if (i1.first() == Range.EndMarker) { - TTY.println("Interval %d has no Range", i1.operandNumber); - TTY.println(i1.logString(this)); - throw new CiBailout(""); - } - - for (Range r = i1.first(); r != Range.EndMarker; r = r.next) { - if (r.from >= r.to) { - TTY.println("Interval %d has zero length range", i1.operandNumber); - TTY.println(i1.logString(this)); - throw new CiBailout(""); - } - } - - for (int j = i + 1; j < len; j++) { - Interval i2 = intervals[j]; - if (i2 == null) { - continue; - } - - // special intervals that are created in MoveResolver - // . ignore them because the range information has no meaning there - if (i1.from() == 1 && i1.to() == 2) { - continue; - } - if (i2.from() == 1 && i2.to() == 2) { - continue; - } - CiValue l1 = i1.location(); - CiValue l2 = i2.location(); - if (i1.intersects(i2) && (l1.equals(l2))) { - if (C1XOptions.DetailedAsserts) { - TTY.println("Intervals %d and %d overlap and have the same register assigned", i1.operandNumber, i2.operandNumber); - TTY.println(i1.logString(this)); - TTY.println(i2.logString(this)); - } - throw new CiBailout(""); - } - } - } - } - - void verifyNoOopsInFixedIntervals() { - Interval fixedIntervals; - Interval otherIntervals; - fixedIntervals = createUnhandledLists(IS_PRECOLORED_INTERVAL, null).first; - // to ensure a walking until the last instruction id, add a dummy interval - // with a high operation id - otherIntervals = new Interval(CiValue.IllegalValue, -1); - otherIntervals.addRange(Integer.MAX_VALUE - 2, Integer.MAX_VALUE - 1); - IntervalWalker iw = new IntervalWalker(this, fixedIntervals, otherIntervals); - - for (int i = 0; i < blockCount(); i++) { - LIRBlock block = blockAt(i); - - List instructions = block.lir().instructionsList(); - - for (int j = 0; j < instructions.size(); j++) { - LIRInstruction op = instructions.get(j); - - if (op.info != null) { - iw.walkBefore(op.id); - boolean checkLive = true; - - // Make sure none of the fixed registers is live across an - // oopmap since we can't handle that correctly. - if (checkLive) { - for (Interval interval = iw.activeLists.get(RegisterBinding.Fixed); interval != Interval.EndMarker; interval = interval.next) { - if (interval.currentTo() > op.id + 1) { - // This interval is live out of this op so make sure - // that this interval represents some value that's - // referenced by this op either as an input or output. - boolean ok = false; - for (LIRInstruction.OperandMode mode : LIRInstruction.OPERAND_MODES) { - int n = op.operandCount(mode); - for (int k = 0; k < n; k++) { - CiValue operand = op.operandAt(mode, k); - if (operand.isRegister()) { - if (intervalFor(operand) == interval) { - ok = true; - break; - } - } - } - } - assert ok : "fixed intervals should never be live across an oopmap point"; - } - } - } - } - } - } - } - - void verifyConstants() { - int numBlocks = blockCount(); - - for (int i = 0; i < numBlocks; i++) { - LIRBlock block = blockAt(i); - CiBitMap liveAtEdge = block.liveIn; - - // visit all operands where the liveAtEdge bit is set - for (int operandNum = liveAtEdge.nextSetBit(0); operandNum >= 0; operandNum = liveAtEdge.nextSetBit(operandNum + 1)) { - if (C1XOptions.TraceLinearScanLevel >= 4) { - TTY.println("checking interval %d of block B%d", operandNum, block.blockID()); - } - CiValue operand = operands.operandFor(operandNum); - assert operand.isVariable() : "value must have variable operand"; - Value value = gen.operands.instructionForResult(((CiVariable) operand)); - assert value != null : "all intervals live across block boundaries must have Value"; - // TKR assert value.asConstant() == null || value.isPinned() : - // "only pinned constants can be alive accross block boundaries"; - } - } - } - - public int numberOfSpillSlots(CiKind kind) { - return compilation.target.spillSlots(kind); - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/alloc/LinearScanWalker.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/alloc/LinearScanWalker.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,980 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.alloc; - -import static com.sun.cri.ci.CiUtil.*; - -import java.util.*; - -import com.sun.c1x.*; -import com.sun.c1x.alloc.Interval.*; -import com.sun.c1x.debug.*; -import com.sun.c1x.lir.*; -import com.sun.c1x.util.*; -import com.sun.cri.ci.*; -import com.sun.cri.ci.CiRegister.*; - -/** - * - * @author Thomas Wuerthinger - */ -final class LinearScanWalker extends IntervalWalker { - - private CiRegister[] availableRegs; - - private final int[] usePos; - private final int[] blockPos; - - private List[] spillIntervals; - - private MoveResolver moveResolver; // for ordering spill moves - - // accessors mapped to same functions in class LinearScan - int blockCount() { - return allocator.blockCount(); - } - - LIRBlock blockAt(int idx) { - return allocator.blockAt(idx); - } - - LIRBlock blockOfOpWithId(int opId) { - return allocator.blockForId(opId); - } - - LinearScanWalker(LinearScan allocator, Interval unhandledFixedFirst, Interval unhandledAnyFirst) { - super(allocator, unhandledFixedFirst, unhandledAnyFirst); - moveResolver = new MoveResolver(allocator); - spillIntervals = Util.uncheckedCast(new List[allocator.registers.length]); - for (int i = 0; i < allocator.registers.length; i++) { - spillIntervals[i] = new ArrayList(2); - } - usePos = new int[allocator.registers.length]; - blockPos = new int[allocator.registers.length]; - } - - void initUseLists(boolean onlyProcessUsePos) { - for (CiRegister register : availableRegs) { - int i = register.number; - usePos[i] = Integer.MAX_VALUE; - - if (!onlyProcessUsePos) { - blockPos[i] = Integer.MAX_VALUE; - spillIntervals[i].clear(); - } - } - } - - void excludeFromUse(Interval i) { - CiValue location = i.location(); - int i1 = location.asRegister().number; - if (i1 >= availableRegs[0].number && i1 <= availableRegs[availableRegs.length - 1].number) { - usePos[i1] = 0; - } - } - - void setUsePos(Interval interval, int usePos, boolean onlyProcessUsePos) { - if (usePos != -1) { - assert usePos != 0 : "must use excludeFromUse to set usePos to 0"; - int i = interval.location().asRegister().number; - if (i >= availableRegs[0].number && i <= availableRegs[availableRegs.length - 1].number) { - if (this.usePos[i] > usePos) { - this.usePos[i] = usePos; - } - if (!onlyProcessUsePos) { - spillIntervals[i].add(interval); - } - } - } - } - - void setBlockPos(Interval i, int blockPos) { - if (blockPos != -1) { - int reg = i.location().asRegister().number; - if (reg >= availableRegs[0].number && reg <= availableRegs[availableRegs.length - 1].number) { - if (this.blockPos[reg] > blockPos) { - this.blockPos[reg] = blockPos; - } - if (usePos[reg] > blockPos) { - usePos[reg] = blockPos; - } - } - } - } - - void freeExcludeActiveFixed() { - Interval interval = activeLists.get(RegisterBinding.Fixed); - while (interval != Interval.EndMarker) { - assert interval.location().isRegister() : "active interval must have a register assigned"; - excludeFromUse(interval); - interval = interval.next; - } - } - - void freeExcludeActiveAny() { - Interval interval = activeLists.get(RegisterBinding.Any); - while (interval != Interval.EndMarker) { - assert interval.location().isRegister() : "active interval must have a register assigned"; - excludeFromUse(interval); - interval = interval.next; - } - } - - void freeCollectInactiveFixed(Interval current) { - Interval interval = inactiveLists.get(RegisterBinding.Fixed); - while (interval != Interval.EndMarker) { - if (current.to() <= interval.currentFrom()) { - assert interval.currentIntersectsAt(current) == -1 : "must not intersect"; - setUsePos(interval, interval.currentFrom(), true); - } else { - setUsePos(interval, interval.currentIntersectsAt(current), true); - } - interval = interval.next; - } - } - - void freeCollectInactiveAny(Interval current) { - Interval interval = inactiveLists.get(RegisterBinding.Any); - while (interval != Interval.EndMarker) { - setUsePos(interval, interval.currentIntersectsAt(current), true); - interval = interval.next; - } - } - - void freeCollectUnhandled(RegisterBinding kind, Interval current) { - Interval interval = unhandledLists.get(kind); - while (interval != Interval.EndMarker) { - setUsePos(interval, interval.intersectsAt(current), true); - if (kind == RegisterBinding.Fixed && current.to() <= interval.from()) { - setUsePos(interval, interval.from(), true); - } - interval = interval.next; - } - } - - void spillExcludeActiveFixed() { - Interval interval = activeLists.get(RegisterBinding.Fixed); - while (interval != Interval.EndMarker) { - excludeFromUse(interval); - interval = interval.next; - } - } - - void spillBlockUnhandledFixed(Interval current) { - Interval interval = unhandledLists.get(RegisterBinding.Fixed); - while (interval != Interval.EndMarker) { - setBlockPos(interval, interval.intersectsAt(current)); - interval = interval.next; - } - } - - void spillBlockInactiveFixed(Interval current) { - Interval interval = inactiveLists.get(RegisterBinding.Fixed); - while (interval != Interval.EndMarker) { - if (current.to() > interval.currentFrom()) { - setBlockPos(interval, interval.currentIntersectsAt(current)); - } else { - assert interval.currentIntersectsAt(current) == -1 : "invalid optimization: intervals intersect"; - } - - interval = interval.next; - } - } - - void spillCollectActiveAny() { - Interval interval = activeLists.get(RegisterBinding.Any); - while (interval != Interval.EndMarker) { - setUsePos(interval, Math.min(interval.nextUsage(RegisterPriority.LiveAtLoopEnd, currentPosition), interval.to()), false); - interval = interval.next; - } - } - - void spillCollectInactiveAny(Interval current) { - Interval interval = inactiveLists.get(RegisterBinding.Any); - while (interval != Interval.EndMarker) { - if (interval.currentIntersects(current)) { - setUsePos(interval, Math.min(interval.nextUsage(RegisterPriority.LiveAtLoopEnd, currentPosition), interval.to()), false); - } - interval = interval.next; - } - } - - void insertMove(int opId, Interval srcIt, Interval dstIt) { - // output all moves here. When source and target are equal, the move is - // optimized away later in assignRegNums - - opId = (opId + 1) & ~1; - LIRBlock opBlock = allocator.blockForId(opId); - assert opId > 0 && allocator.blockForId(opId - 2) == opBlock : "cannot insert move at block boundary"; - - // calculate index of instruction inside instruction list of current block - // the minimal index (for a block with no spill moves) can be calculated because the - // numbering of instructions is known. - // When the block already contains spill moves, the index must be increased until the - // correct index is reached. - List list = opBlock.lir().instructionsList(); - int index = (opId - list.get(0).id) >> 1; - assert list.get(index).id <= opId : "error in calculation"; - - while (list.get(index).id != opId) { - index++; - assert 0 <= index && index < list.size() : "index out of bounds"; - } - assert 1 <= index && index < list.size() : "index out of bounds"; - assert list.get(index).id == opId : "error in calculation"; - - // insert new instruction before instruction at position index - moveResolver.moveInsertPosition(opBlock.lir(), index - 1); - moveResolver.addMapping(srcIt, dstIt); - } - - int findOptimalSplitPos(LIRBlock minBlock, LIRBlock maxBlock, int maxSplitPos) { - int fromBlockNr = minBlock.linearScanNumber(); - int toBlockNr = maxBlock.linearScanNumber(); - - assert 0 <= fromBlockNr && fromBlockNr < blockCount() : "out of range"; - assert 0 <= toBlockNr && toBlockNr < blockCount() : "out of range"; - assert fromBlockNr < toBlockNr : "must cross block boundary"; - - // Try to split at end of maxBlock. If this would be after - // maxSplitPos, then use the begin of maxBlock - int optimalSplitPos = maxBlock.lastLirInstructionId() + 2; - if (optimalSplitPos > maxSplitPos) { - optimalSplitPos = maxBlock.firstLirInstructionId(); - } - - int minLoopDepth = maxBlock.loopDepth(); - for (int i = toBlockNr - 1; i >= fromBlockNr; i--) { - LIRBlock cur = blockAt(i); - - if (cur.loopDepth() < minLoopDepth) { - // block with lower loop-depth found . split at the end of this block - minLoopDepth = cur.loopDepth(); - optimalSplitPos = cur.lastLirInstructionId() + 2; - } - } - assert optimalSplitPos > allocator.maxOpId() || allocator.isBlockBegin(optimalSplitPos) : "algorithm must move split pos to block boundary"; - - return optimalSplitPos; - } - - int findOptimalSplitPos(Interval interval, int minSplitPos, int maxSplitPos, boolean doLoopOptimization) { - int optimalSplitPos = -1; - if (minSplitPos == maxSplitPos) { - // trivial case, no optimization of split position possible - if (C1XOptions.TraceLinearScanLevel >= 4) { - TTY.println(" min-pos and max-pos are equal, no optimization possible"); - } - optimalSplitPos = minSplitPos; - - } else { - assert minSplitPos < maxSplitPos : "must be true then"; - assert minSplitPos > 0 : "cannot access minSplitPos - 1 otherwise"; - - // reason for using minSplitPos - 1: when the minimal split pos is exactly at the - // beginning of a block, then minSplitPos is also a possible split position. - // Use the block before as minBlock, because then minBlock.lastLirInstructionId() + 2 == minSplitPos - LIRBlock minBlock = allocator.blockForId(minSplitPos - 1); - - // reason for using maxSplitPos - 1: otherwise there would be an assert on failure - // when an interval ends at the end of the last block of the method - // (in this case, maxSplitPos == allocator().maxLirOpId() + 2, and there is no - // block at this opId) - LIRBlock maxBlock = allocator.blockForId(maxSplitPos - 1); - - assert minBlock.linearScanNumber() <= maxBlock.linearScanNumber() : "invalid order"; - if (minBlock == maxBlock) { - // split position cannot be moved to block boundary : so split as late as possible - if (C1XOptions.TraceLinearScanLevel >= 4) { - TTY.println(" cannot move split pos to block boundary because minPos and maxPos are in same block"); - } - optimalSplitPos = maxSplitPos; - - } else { - if (interval.hasHoleBetween(maxSplitPos - 1, maxSplitPos) && !allocator.isBlockBegin(maxSplitPos)) { - // Do not move split position if the interval has a hole before maxSplitPos. - // Intervals resulting from Phi-Functions have more than one definition (marked - // as mustHaveRegister) with a hole before each definition. When the register is needed - // for the second definition : an earlier reloading is unnecessary. - if (C1XOptions.TraceLinearScanLevel >= 4) { - TTY.println(" interval has hole just before maxSplitPos, so splitting at maxSplitPos"); - } - optimalSplitPos = maxSplitPos; - - } else { - // seach optimal block boundary between minSplitPos and maxSplitPos - if (C1XOptions.TraceLinearScanLevel >= 4) { - TTY.println(" moving split pos to optimal block boundary between block B%d and B%d", minBlock.blockID(), maxBlock.blockID()); - } - - if (doLoopOptimization) { - // Loop optimization: if a loop-end marker is found between min- and max-position : - // then split before this loop - int loopEndPos = interval.nextUsageExact(RegisterPriority.LiveAtLoopEnd, minBlock.lastLirInstructionId() + 2); - if (C1XOptions.TraceLinearScanLevel >= 4) { - TTY.println(" loop optimization: loop end found at pos %d", loopEndPos); - } - - assert loopEndPos > minSplitPos : "invalid order"; - if (loopEndPos < maxSplitPos) { - // loop-end marker found between min- and max-position - // if it is not the end marker for the same loop as the min-position : then move - // the max-position to this loop block. - // Desired result: uses tagged as shouldHaveRegister inside a loop cause a reloading - // of the interval (normally, only mustHaveRegister causes a reloading) - LIRBlock loopBlock = allocator.blockForId(loopEndPos); - - if (C1XOptions.TraceLinearScanLevel >= 4) { - TTY.println(" interval is used in loop that ends in block B%d, so trying to move maxBlock back from B%d to B%d", loopBlock.blockID(), maxBlock.blockID(), loopBlock.blockID()); - } - assert loopBlock != minBlock : "loopBlock and minBlock must be different because block boundary is needed between"; - - optimalSplitPos = findOptimalSplitPos(minBlock, loopBlock, loopBlock.lastLirInstructionId() + 2); - if (optimalSplitPos == loopBlock.lastLirInstructionId() + 2) { - optimalSplitPos = -1; - if (C1XOptions.TraceLinearScanLevel >= 4) { - TTY.println(" loop optimization not necessary"); - } - } else { - if (C1XOptions.TraceLinearScanLevel >= 4) { - TTY.println(" loop optimization successful"); - } - } - } - } - - if (optimalSplitPos == -1) { - // not calculated by loop optimization - optimalSplitPos = findOptimalSplitPos(minBlock, maxBlock, maxSplitPos); - } - } - } - } - if (C1XOptions.TraceLinearScanLevel >= 4) { - TTY.println(" optimal split position: %d", optimalSplitPos); - } - - return optimalSplitPos; - } - - // split an interval at the optimal position between minSplitPos and - // maxSplitPos in two parts: - // 1) the left part has already a location assigned - // 2) the right part is sorted into to the unhandled-list - void splitBeforeUsage(Interval interval, int minSplitPos, int maxSplitPos) { - if (C1XOptions.TraceLinearScanLevel >= 2) { - TTY.println("----- splitting interval: "); - } - if (C1XOptions.TraceLinearScanLevel >= 4) { - TTY.println(interval.logString(allocator)); - } - if (C1XOptions.TraceLinearScanLevel >= 2) { - TTY.println(" between %d and %d", minSplitPos, maxSplitPos); - } - - assert interval.from() < minSplitPos : "cannot split at start of interval"; - assert currentPosition < minSplitPos : "cannot split before current position"; - assert minSplitPos <= maxSplitPos : "invalid order"; - assert maxSplitPos <= interval.to() : "cannot split after end of interval"; - - int optimalSplitPos = findOptimalSplitPos(interval, minSplitPos, maxSplitPos, true); - - assert minSplitPos <= optimalSplitPos && optimalSplitPos <= maxSplitPos : "out of range"; - assert optimalSplitPos <= interval.to() : "cannot split after end of interval"; - assert optimalSplitPos > interval.from() : "cannot split at start of interval"; - - if (optimalSplitPos == interval.to() && interval.nextUsage(RegisterPriority.MustHaveRegister, minSplitPos) == Integer.MAX_VALUE) { - // the split position would be just before the end of the interval - // . no split at all necessary - if (C1XOptions.TraceLinearScanLevel >= 4) { - TTY.println(" no split necessary because optimal split position is at end of interval"); - } - return; - } - - // must calculate this before the actual split is performed and before split position is moved to odd opId - boolean moveNecessary = !allocator.isBlockBegin(optimalSplitPos) && !interval.hasHoleBetween(optimalSplitPos - 1, optimalSplitPos); - - if (!allocator.isBlockBegin(optimalSplitPos)) { - // move position before actual instruction (odd opId) - optimalSplitPos = (optimalSplitPos - 1) | 1; - } - - if (C1XOptions.TraceLinearScanLevel >= 4) { - TTY.println(" splitting at position %d", optimalSplitPos); - } - assert allocator.isBlockBegin(optimalSplitPos) || (optimalSplitPos % 2 == 1) : "split pos must be odd when not on block boundary"; - assert !allocator.isBlockBegin(optimalSplitPos) || (optimalSplitPos % 2 == 0) : "split pos must be even on block boundary"; - - Interval splitPart = interval.split(optimalSplitPos, allocator); - - allocator.copyRegisterFlags(interval, splitPart); - splitPart.setInsertMoveWhenActivated(moveNecessary); - - assert splitPart.from() >= current.currentFrom() : "cannot append new interval before current walk position"; - unhandledLists.addToListSortedByStartAndUsePositions(RegisterBinding.Any, splitPart); - - if (C1XOptions.TraceLinearScanLevel >= 2) { - TTY.println(" split interval in two parts (insertMoveWhenActivated: %b)", moveNecessary); - } - if (C1XOptions.TraceLinearScanLevel >= 2) { - TTY.print(" "); - TTY.println(interval.logString(allocator)); - TTY.print(" "); - TTY.println(splitPart.logString(allocator)); - } - } - -// split an interval at the optimal position between minSplitPos and -// maxSplitPos in two parts: -// 1) the left part has already a location assigned -// 2) the right part is always on the stack and therefore ignored in further processing - - void splitForSpilling(Interval interval) { - // calculate allowed range of splitting position - int maxSplitPos = currentPosition; - int minSplitPos = Math.max(interval.previousUsage(RegisterPriority.ShouldHaveRegister, maxSplitPos) + 1, interval.from()); - - if (C1XOptions.TraceLinearScanLevel >= 2) { - TTY.print("----- splitting and spilling interval: "); - TTY.println(interval.logString(allocator)); - TTY.println(" between %d and %d", minSplitPos, maxSplitPos); - } - - assert interval.state == State.Active : "why spill interval that is not active?"; - assert interval.from() <= minSplitPos : "cannot split before start of interval"; - assert minSplitPos <= maxSplitPos : "invalid order"; - assert maxSplitPos < interval.to() : "cannot split at end end of interval"; - assert currentPosition < interval.to() : "interval must not end before current position"; - - if (minSplitPos == interval.from()) { - // the whole interval is never used, so spill it entirely to memory - if (C1XOptions.TraceLinearScanLevel >= 2) { - TTY.println(" spilling entire interval because split pos is at beginning of interval"); - TTY.println(" use positions: " + interval.usePosList().size()); - } - assert interval.firstUsage(RegisterPriority.ShouldHaveRegister) > currentPosition : "interval must not have use position before currentPosition"; - - allocator.assignSpillSlot(interval); - allocator.changeSpillState(interval, minSplitPos); - - // Also kick parent intervals out of register to memory when they have no use - // position. This avoids short interval in register surrounded by intervals in - // memory . avoid useless moves from memory to register and back - Interval parent = interval; - while (parent != null && parent.isSplitChild()) { - parent = parent.getSplitChildBeforeOpId(parent.from()); - - if (parent.location().isRegister()) { - if (parent.firstUsage(RegisterPriority.ShouldHaveRegister) == Integer.MAX_VALUE) { - // parent is never used, so kick it out of its assigned register - if (C1XOptions.TraceLinearScanLevel >= 4) { - TTY.println(" kicking out interval %d out of its register because it is never used", parent.operandNumber); - } - allocator.assignSpillSlot(parent); - } else { - // do not go further back because the register is actually used by the interval - parent = null; - } - } - } - - } else { - // search optimal split pos, split interval and spill only the right hand part - int optimalSplitPos = findOptimalSplitPos(interval, minSplitPos, maxSplitPos, false); - - assert minSplitPos <= optimalSplitPos && optimalSplitPos <= maxSplitPos : "out of range"; - assert optimalSplitPos < interval.to() : "cannot split at end of interval"; - assert optimalSplitPos >= interval.from() : "cannot split before start of interval"; - - if (!allocator.isBlockBegin(optimalSplitPos)) { - // move position before actual instruction (odd opId) - optimalSplitPos = (optimalSplitPos - 1) | 1; - } - - if (C1XOptions.TraceLinearScanLevel >= 4) { - TTY.println(" splitting at position %d", optimalSplitPos); - } - assert allocator.isBlockBegin(optimalSplitPos) || (optimalSplitPos % 2 == 1) : "split pos must be odd when not on block boundary"; - assert !allocator.isBlockBegin(optimalSplitPos) || (optimalSplitPos % 2 == 0) : "split pos must be even on block boundary"; - - Interval spilledPart = interval.split(optimalSplitPos, allocator); - allocator.assignSpillSlot(spilledPart); - allocator.changeSpillState(spilledPart, optimalSplitPos); - - if (!allocator.isBlockBegin(optimalSplitPos)) { - if (C1XOptions.TraceLinearScanLevel >= 4) { - TTY.println(" inserting move from interval %d to %d", interval.operandNumber, spilledPart.operandNumber); - } - insertMove(optimalSplitPos, interval, spilledPart); - } - - // the currentSplitChild is needed later when moves are inserted for reloading - assert spilledPart.currentSplitChild() == interval : "overwriting wrong currentSplitChild"; - spilledPart.makeCurrentSplitChild(); - - if (C1XOptions.TraceLinearScanLevel >= 2) { - TTY.println(" split interval in two parts"); - TTY.print(" "); - TTY.println(interval.logString(allocator)); - TTY.print(" "); - TTY.println(spilledPart.logString(allocator)); - } - } - } - - void splitStackInterval(Interval interval) { - int minSplitPos = currentPosition + 1; - int maxSplitPos = Math.min(interval.firstUsage(RegisterPriority.ShouldHaveRegister), interval.to()); - - splitBeforeUsage(interval, minSplitPos, maxSplitPos); - } - - void splitWhenPartialRegisterAvailable(Interval interval, int registerAvailableUntil) { - int minSplitPos = Math.max(interval.previousUsage(RegisterPriority.ShouldHaveRegister, registerAvailableUntil), interval.from() + 1); - splitBeforeUsage(interval, minSplitPos, registerAvailableUntil); - } - - void splitAndSpillInterval(Interval interval) { - assert interval.state == State.Active || interval.state == State.Inactive : "other states not allowed"; - - int currentPos = currentPosition; - if (interval.state == State.Inactive) { - // the interval is currently inactive, so no spill slot is needed for now. - // when the split part is activated, the interval has a new chance to get a register, - // so in the best case no stack slot is necessary - assert interval.hasHoleBetween(currentPos - 1, currentPos + 1) : "interval can not be inactive otherwise"; - splitBeforeUsage(interval, currentPos + 1, currentPos + 1); - - } else { - // search the position where the interval must have a register and split - // at the optimal position before. - // The new created part is added to the unhandled list and will get a register - // when it is activated - int minSplitPos = currentPos + 1; - int maxSplitPos = Math.min(interval.nextUsage(RegisterPriority.MustHaveRegister, minSplitPos), interval.to()); - - splitBeforeUsage(interval, minSplitPos, maxSplitPos); - - assert interval.nextUsage(RegisterPriority.MustHaveRegister, currentPos) == Integer.MAX_VALUE : "the remaining part is spilled to stack and therefore has no register"; - splitForSpilling(interval); - } - } - - boolean allocFreeRegister(Interval interval) { - if (C1XOptions.TraceLinearScanLevel >= 2) { - TTY.println("trying to find free register for " + interval.logString(allocator)); - } - - initUseLists(true); - freeExcludeActiveFixed(); - freeExcludeActiveAny(); - freeCollectInactiveFixed(interval); - freeCollectInactiveAny(interval); - // freeCollectUnhandled(fixedKind, cur); - assert unhandledLists.get(RegisterBinding.Fixed) == Interval.EndMarker : "must not have unhandled fixed intervals because all fixed intervals have a use at position 0"; - - // usePos contains the start of the next interval that has this register assigned - // (either as a fixed register or a normal allocated register in the past) - // only intervals overlapping with cur are processed, non-overlapping invervals can be ignored safely - if (C1XOptions.TraceLinearScanLevel >= 4) { - TTY.println(" state of registers:"); - for (CiRegister register : availableRegs) { - int i = register.number; - TTY.println(" reg %d: usePos: %d", register.number, usePos[i]); - } - } - - CiRegister hint = null; - Interval locationHint = interval.locationHint(true, allocator); - if (locationHint != null && locationHint.location() != null && locationHint.location().isRegister()) { - hint = locationHint.location().asRegister(); - if (C1XOptions.TraceLinearScanLevel >= 4) { - TTY.println(" hint register %d from interval %s", hint.number, locationHint.logString(allocator)); - } - } - assert interval.location() == null : "register already assigned to interval"; - - // the register must be free at least until this position - int regNeededUntil = interval.from() + 1; - int intervalTo = interval.to(); - - boolean needSplit = false; - int splitPos = -1; - - CiRegister reg = null; - CiRegister minFullReg = null; - CiRegister maxPartialReg = null; - - for (int i = 0; i < availableRegs.length; ++i) { - CiRegister availableReg = availableRegs[i]; - int number = availableReg.number; - if (usePos[number] >= intervalTo) { - // this register is free for the full interval - if (minFullReg == null || availableReg == hint || (usePos[number] < usePos[minFullReg.number] && minFullReg != hint)) { - minFullReg = availableReg; - } - } else if (usePos[number] > regNeededUntil) { - // this register is at least free until regNeededUntil - if (maxPartialReg == null || availableReg == hint || (usePos[number] > usePos[maxPartialReg.number] && maxPartialReg != hint)) { - maxPartialReg = availableReg; - } - } - } - - if (minFullReg != null) { - reg = minFullReg; - } else if (maxPartialReg != null) { - needSplit = true; - reg = maxPartialReg; - } else { - return false; - } - - splitPos = usePos[reg.number]; - interval.assignLocation(reg.asValue(interval.kind())); - if (C1XOptions.TraceLinearScanLevel >= 2) { - TTY.println("selected register %d", reg.number); - } - - assert splitPos > 0 : "invalid splitPos"; - if (needSplit) { - // register not available for full interval, so split it - splitWhenPartialRegisterAvailable(interval, splitPos); - } - - // only return true if interval is completely assigned - return true; - } - - CiRegister findLockedRegister(int regNeededUntil, int intervalTo, CiValue ignoreReg, boolean[] needSplit) { - int maxReg = -1; - CiRegister ignore = ignoreReg.isRegister() ? ignoreReg.asRegister() : null; - - for (CiRegister reg : availableRegs) { - int i = reg.number; - if (reg == ignore) { - // this register must be ignored - - } else if (usePos[i] > regNeededUntil) { - if (maxReg == -1 || (usePos[i] > usePos[maxReg])) { - maxReg = i; - } - } - } - - if (maxReg != -1) { - if (blockPos[maxReg] <= intervalTo) { - needSplit[0] = true; - } - return availableRegs[maxReg]; - } - - return null; - } - - void splitAndSpillIntersectingIntervals(CiRegister reg) { - assert reg != null : "no register assigned"; - - for (int i = 0; i < spillIntervals[reg.number].size(); i++) { - Interval interval = spillIntervals[reg.number].get(i); - removeFromList(interval); - splitAndSpillInterval(interval); - } - } - - // Split an Interval and spill it to memory so that cur can be placed in a register - void allocLockedRegister(Interval interval) { - if (C1XOptions.TraceLinearScanLevel >= 2) { - TTY.println("need to split and spill to get register for " + interval.logString(allocator)); - } - - // collect current usage of registers - initUseLists(false); - spillExcludeActiveFixed(); - // spillBlockUnhandledFixed(cur); - assert unhandledLists.get(RegisterBinding.Fixed) == Interval.EndMarker : "must not have unhandled fixed intervals because all fixed intervals have a use at position 0"; - spillBlockInactiveFixed(interval); - spillCollectActiveAny(); - spillCollectInactiveAny(interval); - - if (C1XOptions.TraceLinearScanLevel >= 4) { - TTY.println(" state of registers:"); - for (CiRegister reg : availableRegs) { - int i = reg.number; - TTY.print(" reg %d: usePos: %d, blockPos: %d, intervals: ", i, usePos[i], blockPos[i]); - for (int j = 0; j < spillIntervals[i].size(); j++) { - TTY.print("%d ", spillIntervals[i].get(j).operandNumber); - } - TTY.println(); - } - } - - // the register must be free at least until this position - int firstUsage = interval.firstUsage(RegisterPriority.MustHaveRegister); - int regNeededUntil = Math.min(firstUsage, interval.from() + 1); - int intervalTo = interval.to(); - assert regNeededUntil > 0 && regNeededUntil < Integer.MAX_VALUE : "interval has no use"; - - CiRegister reg = null; - CiRegister ignore = interval.location() != null && interval.location().isRegister() ? interval.location().asRegister() : null; - for (CiRegister availableReg : availableRegs) { - int number = availableReg.number; - if (availableReg == ignore) { - // this register must be ignored - } else if (usePos[number] > regNeededUntil) { - if (reg == null || (usePos[number] > usePos[reg.number])) { - reg = availableReg; - } - } - } - - if (reg == null || usePos[reg.number] <= firstUsage) { - // the first use of cur is later than the spilling position -> spill cur - if (C1XOptions.TraceLinearScanLevel >= 4) { - TTY.println("able to spill current interval. firstUsage(register): %d, usePos: %d", firstUsage, reg == null ? 0 : usePos[reg.number]); - } - - if (firstUsage <= interval.from() + 1) { - assert false : "cannot spill interval that is used in first instruction (possible reason: no register found) firstUsage=" + firstUsage + ", interval.from()=" + interval.from(); - // assign a reasonable register and do a bailout in product mode to avoid errors - allocator.assignSpillSlot(interval); - throw new CiBailout("LinearScan: no register found"); - } - - splitAndSpillInterval(interval); - return; - } - - boolean needSplit = blockPos[reg.number] <= intervalTo; - - int splitPos = blockPos[reg.number]; - - if (C1XOptions.TraceLinearScanLevel >= 4) { - TTY.println("decided to use register %d", reg.number); - } - assert splitPos > 0 : "invalid splitPos"; - assert needSplit || splitPos > interval.from() : "splitting interval at from"; - - interval.assignLocation(reg.asValue(interval.kind())); - if (needSplit) { - // register not available for full interval : so split it - splitWhenPartialRegisterAvailable(interval, splitPos); - } - - // perform splitting and spilling for all affected intervals - splitAndSpillIntersectingIntervals(reg); - } - - boolean noAllocationPossible(Interval interval) { - - if (compilation.target.arch.isX86()) { - // fast calculation of intervals that can never get a register because the - // the next instruction is a call that blocks all registers - // Note: this does not work if callee-saved registers are available (e.g. on Sparc) - - // check if this interval is the result of a split operation - // (an interval got a register until this position) - int pos = interval.from(); - if (isOdd(pos)) { - // the current instruction is a call that blocks all registers - if (pos < allocator.maxOpId() && allocator.hasCall(pos + 1) && interval.to() > pos + 1) { - if (C1XOptions.TraceLinearScanLevel >= 4) { - TTY.println(" free register cannot be available because all registers blocked by following call"); - } - - // safety check that there is really no register available - assert !allocFreeRegister(interval) : "found a register for this interval"; - return true; - } - - } - } - return false; - } - - void initVarsForAlloc(Interval interval) { - EnumMap categorizedRegs = allocator.compilation.registerConfig.getCategorizedAllocatableRegisters(); - if (allocator.operands.mustBeByteRegister(interval.operand)) { - assert interval.kind() != CiKind.Float && interval.kind() != CiKind.Double : "cpu regs only"; - availableRegs = categorizedRegs.get(RegisterFlag.Byte); - } else if (interval.kind() == CiKind.Float || interval.kind() == CiKind.Double) { - availableRegs = categorizedRegs.get(RegisterFlag.FPU); - } else { - availableRegs = categorizedRegs.get(RegisterFlag.CPU); - } - } - - boolean isMove(LIRInstruction op, Interval from, Interval to) { - if (op.code != LIROpcode.Move) { - return false; - } - assert op instanceof LIROp1 : "move must be LIROp1"; - - CiValue input = ((LIROp1) op).operand(); - CiValue result = ((LIROp1) op).result(); - return input.isVariable() && result.isVariable() && input == from.operand && result == to.operand; - } - - // optimization (especially for phi functions of nested loops): - // assign same spill slot to non-intersecting intervals - void combineSpilledIntervals(Interval interval) { - if (interval.isSplitChild()) { - // optimization is only suitable for split parents - return; - } - - Interval registerHint = interval.locationHint(false, allocator); - if (registerHint == null) { - // cur is not the target of a move : otherwise registerHint would be set - return; - } - assert registerHint.isSplitParent() : "register hint must be split parent"; - - if (interval.spillState() != SpillState.NoOptimization || registerHint.spillState() != SpillState.NoOptimization) { - // combining the stack slots for intervals where spill move optimization is applied - // is not benefitial and would cause problems - return; - } - - int beginPos = interval.from(); - int endPos = interval.to(); - if (endPos > allocator.maxOpId() || isOdd(beginPos) || isOdd(endPos)) { - // safety check that lirOpWithId is allowed - return; - } - - if (!isMove(allocator.instructionForId(beginPos), registerHint, interval) || !isMove(allocator.instructionForId(endPos), interval, registerHint)) { - // cur and registerHint are not connected with two moves - return; - } - - Interval beginHint = registerHint.getSplitChildAtOpId(beginPos, LIRInstruction.OperandMode.Input, allocator); - Interval endHint = registerHint.getSplitChildAtOpId(endPos, LIRInstruction.OperandMode.Output, allocator); - if (beginHint == endHint || beginHint.to() != beginPos || endHint.from() != endPos) { - // registerHint must be split : otherwise the re-writing of use positions does not work - return; - } - - assert beginHint.location() != null : "must have register assigned"; - assert endHint.location() == null : "must not have register assigned"; - assert interval.firstUsage(RegisterPriority.MustHaveRegister) == beginPos : "must have use position at begin of interval because of move"; - assert endHint.firstUsage(RegisterPriority.MustHaveRegister) == endPos : "must have use position at begin of interval because of move"; - - if (beginHint.location().isRegister()) { - // registerHint is not spilled at beginPos : so it would not be benefitial to immediately spill cur - return; - } - assert registerHint.spillSlot() != null : "must be set when part of interval was spilled"; - - // modify intervals such that cur gets the same stack slot as registerHint - // delete use positions to prevent the intervals to get a register at beginning - interval.setSpillSlot(registerHint.spillSlot()); - interval.removeFirstUsePos(); - endHint.removeFirstUsePos(); - } - - // allocate a physical register or memory location to an interval - @Override - boolean activateCurrent() { - Interval interval = current; - boolean result = true; - - if (C1XOptions.TraceLinearScanLevel >= 2) { - TTY.println("+++++ activating interval " + interval.logString(allocator)); - } - - if (C1XOptions.TraceLinearScanLevel >= 4) { - TTY.println(" splitParent: %s, insertMoveWhenActivated: %b", interval.splitParent().operandNumber, interval.insertMoveWhenActivated()); - } - - final CiValue operand = interval.operand; - if (interval.location() != null && interval.location().isStackSlot()) { - // activating an interval that has a stack slot assigned . split it at first use position - // used for method parameters - if (C1XOptions.TraceLinearScanLevel >= 4) { - TTY.println(" interval has spill slot assigned (method parameter) . split it before first use"); - } - splitStackInterval(interval); - result = false; - - } else { - if (operand.isVariable() && allocator.operands.mustStartInMemory((CiVariable) operand)) { - assert interval.location() == null : "register already assigned"; - allocator.assignSpillSlot(interval); - - if (!allocator.operands.mustStayInMemory((CiVariable) operand)) { - // activating an interval that must start in a stack slot but may get a register later - // used for lirRoundfp: rounding is done by store to stack and reload later - if (C1XOptions.TraceLinearScanLevel >= 4) { - TTY.println(" interval must start in stack slot . split it before first use"); - } - splitStackInterval(interval); - } - - result = false; - } else if (interval.location() == null) { - // interval has not assigned register . normal allocation - // (this is the normal case for most intervals) - if (C1XOptions.TraceLinearScanLevel >= 4) { - TTY.println(" normal allocation of register"); - } - - // assign same spill slot to non-intersecting intervals - combineSpilledIntervals(interval); - - initVarsForAlloc(interval); - if (noAllocationPossible(interval) || !allocFreeRegister(interval)) { - // no empty register available. - // split and spill another interval so that this interval gets a register - allocLockedRegister(interval); - } - - // spilled intervals need not be move to active-list - if (!interval.location().isRegister()) { - result = false; - } - } - } - - // load spilled values that become active from stack slot to register - if (interval.insertMoveWhenActivated()) { - assert interval.isSplitChild(); - assert interval.currentSplitChild() != null; - assert interval.currentSplitChild().operand != operand : "cannot insert move between same interval"; - if (C1XOptions.TraceLinearScanLevel >= 4) { - TTY.println("Inserting move from interval %d to %d because insertMoveWhenActivated is set", interval.currentSplitChild().operandNumber, interval.operandNumber); - } - - insertMove(interval.from(), interval.currentSplitChild(), interval); - } - interval.makeCurrentSplitChild(); - - return result; // true = interval is moved to active list - } - - public void finishAllocation() { - // must be called when all intervals are allocated - moveResolver.resolveAndAppendMoves(); - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/alloc/MoveResolver.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/alloc/MoveResolver.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,367 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.alloc; - -import java.util.*; - -import com.sun.c1x.*; -import com.sun.c1x.debug.*; -import com.sun.c1x.lir.*; -import com.sun.c1x.util.*; -import com.sun.cri.ci.*; - -/** - * - * @author Thomas Wuerthinger - */ -final class MoveResolver { - - private final LinearScan allocator; - - private LIRList insertList; - private int insertIdx; - private LIRInsertionBuffer insertionBuffer; // buffer where moves are inserted - - private final List mappingFrom; - private final List mappingFromOpr; - private final List mappingTo; - private boolean multipleReadsAllowed; - private final int[] registerBlocked; - - private int registerBlocked(int reg) { - return registerBlocked[reg]; - } - - private void setRegisterBlocked(int reg, int direction) { - assert direction == 1 || direction == -1 : "out of bounds"; - registerBlocked[reg] += direction; - } - - void setMultipleReadsAllowed() { - multipleReadsAllowed = true; - } - - boolean hasMappings() { - return mappingFrom.size() > 0; - } - - MoveResolver(LinearScan allocator) { - - this.allocator = allocator; - this.multipleReadsAllowed = false; - this.mappingFrom = new ArrayList(8); - this.mappingFromOpr = new ArrayList(8); - this.mappingTo = new ArrayList(8); - this.insertIdx = -1; - this.insertionBuffer = new LIRInsertionBuffer(); - this.registerBlocked = new int[allocator.registers.length]; - assert checkEmpty(); - } - - boolean checkEmpty() { - assert mappingFrom.size() == 0 && mappingFromOpr.size() == 0 && mappingTo.size() == 0 : "list must be empty before and after processing"; - for (int i = 0; i < allocator.registers.length; i++) { - assert registerBlocked(i) == 0 : "register map must be empty before and after processing"; - } - assert !multipleReadsAllowed : "must have default value"; - return true; - } - - private boolean verifyBeforeResolve() { - assert mappingFrom.size() == mappingFromOpr.size() : "length must be equal"; - assert mappingFrom.size() == mappingTo.size() : "length must be equal"; - assert insertList != null && insertIdx != -1 : "insert position not set"; - - int i; - int j; - if (!multipleReadsAllowed) { - for (i = 0; i < mappingFrom.size(); i++) { - for (j = i + 1; j < mappingFrom.size(); j++) { - assert mappingFrom.get(i) == null || mappingFrom.get(i) != mappingFrom.get(j) : "cannot read from same interval twice"; - } - } - } - - for (i = 0; i < mappingTo.size(); i++) { - for (j = i + 1; j < mappingTo.size(); j++) { - assert mappingTo.get(i) != mappingTo.get(j) : "cannot write to same interval twice"; - } - } - - HashSet usedRegs = new HashSet(); - if (!multipleReadsAllowed) { - for (i = 0; i < mappingFrom.size(); i++) { - Interval interval = mappingFrom.get(i); - if (interval != null) { - boolean unique = usedRegs.add(interval.location()); - assert unique : "cannot read from same register twice"; - } - } - } - - usedRegs.clear(); - for (i = 0; i < mappingTo.size(); i++) { - Interval interval = mappingTo.get(i); - boolean unique = usedRegs.add(interval.location()); - assert unique : "cannot write to same register twice"; - } - - usedRegs.clear(); - for (i = 0; i < mappingFrom.size(); i++) { - Interval interval = mappingFrom.get(i); - if (interval != null && !interval.location().isRegister()) { - usedRegs.add(interval.location()); - } - } - for (i = 0; i < mappingTo.size(); i++) { - Interval interval = mappingTo.get(i); - assert !usedRegs.contains(interval.location()) || interval.location() == mappingFrom.get(i).location() : "stack slots used in mappingFrom must be disjoint to mappingTo"; - } - - return true; - } - - // mark assignedReg and assignedRegHi of the interval as blocked - private void blockRegisters(Interval interval) { - CiValue location = interval.location(); - if (location.isRegister()) { - int reg = location.asRegister().number; - assert multipleReadsAllowed || registerBlocked(reg) == 0 : "register already marked as used"; - setRegisterBlocked(reg, 1); - } - } - - // mark assignedReg and assignedRegHi of the interval as unblocked - private void unblockRegisters(Interval interval) { - CiValue location = interval.location(); - if (location.isRegister()) { - int reg = location.asRegister().number; - assert registerBlocked(reg) > 0 : "register already marked as unused"; - setRegisterBlocked(reg, -1); - } - } - - /** - * Checks if the {@linkplain Interval#location() location} of {@code to} is not blocked - * or is only blocked by {@code from}. - */ - private boolean safeToProcessMove(Interval from, Interval to) { - CiValue fromReg = from != null ? from.location() : null; - - CiValue reg = to.location(); - if (reg.isRegister()) { - if (registerBlocked(reg.asRegister().number) > 1 || (registerBlocked(reg.asRegister().number) == 1 && reg != fromReg)) { - return false; - } - } - - return true; - } - - private void createInsertionBuffer(LIRList list) { - assert !insertionBuffer.initialized() : "overwriting existing buffer"; - insertionBuffer.init(list); - } - - private void appendInsertionBuffer() { - if (insertionBuffer.initialized()) { - insertionBuffer.lirList().append(insertionBuffer); - } - assert !insertionBuffer.initialized() : "must be uninitialized now"; - - insertList = null; - insertIdx = -1; - } - - private void insertMove(Interval fromInterval, Interval toInterval) { - assert fromInterval.operand != toInterval.operand : "from and to interval equal: " + fromInterval; - assert Util.archKindsEqual(fromInterval.kind(), toInterval.kind()) : "move between different types"; - assert insertList != null && insertIdx != -1 : "must setup insert position first"; - assert insertionBuffer.lirList() == insertList : "wrong insertion buffer"; - - CiValue fromOpr = fromInterval.operand; - CiValue toOpr = toInterval.operand; - - insertionBuffer.move(insertIdx, fromOpr, toOpr, null); - - if (C1XOptions.TraceLinearScanLevel >= 4) { - TTY.println("MoveResolver: inserted move from %d (%s) to %d (%s)", fromInterval.operandNumber, fromInterval.location(), toInterval.operandNumber, toInterval.location()); - } - } - - private void insertMove(CiValue fromOpr, Interval toInterval) { - assert Util.archKindsEqual(fromOpr.kind, toInterval.kind()) : "move between different types"; - assert insertList != null && insertIdx != -1 : "must setup insert position first"; - assert insertionBuffer.lirList() == insertList : "wrong insertion buffer"; - - CiValue toOpr = toInterval.operand; - insertionBuffer.move(insertIdx, fromOpr, toOpr, null); - - if (C1XOptions.TraceLinearScanLevel >= 4) { - TTY.print("MoveResolver: inserted move from constant %s to %d (%s)", fromOpr, toInterval.operandNumber, toInterval.location()); - } - } - - private void resolveMappings() { - //if (C1XOptions.TraceLinearScanLevel >= 4) TTY.println("MoveResolver: resolving mappings for Block B%d, index %d", insertList.block() != null ? insertList.block().blockID : -1, insertIdx); - assert verifyBeforeResolve(); - - // Block all registers that are used as input operands of a move. - // When a register is blocked, no move to this register is emitted. - // This is necessary for detecting cycles in moves. - int i; - for (i = mappingFrom.size() - 1; i >= 0; i--) { - Interval fromInterval = mappingFrom.get(i); - if (fromInterval != null) { - blockRegisters(fromInterval); - } - } - - int spillCandidate = -1; - while (mappingFrom.size() > 0) { - boolean processedInterval = false; - - for (i = mappingFrom.size() - 1; i >= 0; i--) { - Interval fromInterval = mappingFrom.get(i); - Interval toInterval = mappingTo.get(i); - - if (safeToProcessMove(fromInterval, toInterval)) { - // this interval can be processed because target is free - if (fromInterval != null) { - insertMove(fromInterval, toInterval); - unblockRegisters(fromInterval); - } else { - insertMove(mappingFromOpr.get(i), toInterval); - } - mappingFrom.remove(i); - mappingFromOpr.remove(i); - mappingTo.remove(i); - - processedInterval = true; - } else if (fromInterval != null && fromInterval.location().isRegister()) { - // this interval cannot be processed now because target is not free - // it starts in a register, so it is a possible candidate for spilling - spillCandidate = i; - } - } - - if (!processedInterval) { - // no move could be processed because there is a cycle in the move list - // (e.g. r1 . r2, r2 . r1), so one interval must be spilled to memory - assert spillCandidate != -1 : "no interval in register for spilling found"; - - // create a new spill interval and assign a stack slot to it - Interval fromInterval = mappingFrom.get(spillCandidate); - Interval spillInterval = allocator.createDerivedInterval(fromInterval); - spillInterval.setKind(fromInterval.kind()); - - // add a dummy range because real position is difficult to calculate - // Note: this range is a special case when the integrity of the allocation is checked - spillInterval.addRange(1, 2); - - // do not allocate a new spill slot for temporary interval, but - // use spill slot assigned to fromInterval. Otherwise moves from - // one stack slot to another can happen (not allowed by LIRAssembler - CiStackSlot spillSlot = fromInterval.spillSlot(); - if (spillSlot == null) { - spillSlot = allocator.allocateSpillSlot(spillInterval.kind()); - fromInterval.setSpillSlot(spillSlot); - } - spillInterval.assignLocation(spillSlot); - - if (C1XOptions.TraceLinearScanLevel >= 4) { - TTY.println("created new Interval %s for spilling", spillInterval.operand); - } - - // insert a move from register to stack and update the mapping - insertMove(fromInterval, spillInterval); - mappingFrom.set(spillCandidate, spillInterval); - unblockRegisters(fromInterval); - } - } - - // reset to default value - multipleReadsAllowed = false; - - // check that all intervals have been processed - assert checkEmpty(); - } - - void setInsertPosition(LIRList insertList, int insertIdx) { - //if (C1XOptions.TraceLinearScanLevel >= 4) TTY.println("MoveResolver: setting insert position to Block B%d, index %d", insertList.block() != null ? insertList.block().blockID : -1, insertIdx); - assert this.insertList == null && this.insertIdx == -1 : "use moveInsertPosition instead of setInsertPosition when data already set"; - - createInsertionBuffer(insertList); - this.insertList = insertList; - this.insertIdx = insertIdx; - } - - void moveInsertPosition(LIRList insertList, int insertIdx) { - //if (C1XOptions.TraceLinearScanLevel >= 4) TTY.println("MoveResolver: moving insert position to Block B%d, index %d", (insertList != null && insertList.block() != null) ? insertList.block().blockID : -1, insertIdx); - - if (this.insertList != null && (this.insertList != insertList || this.insertIdx != insertIdx)) { - // insert position changed . resolve current mappings - resolveMappings(); - } - - if (this.insertList != insertList) { - // block changed . append insertionBuffer because it is - // bound to a specific block and create a new insertionBuffer - appendInsertionBuffer(); - createInsertionBuffer(insertList); - } - - this.insertList = insertList; - this.insertIdx = insertIdx; - } - - void addMapping(Interval fromInterval, Interval toInterval) { - if (C1XOptions.TraceLinearScanLevel >= 4) { - TTY.println("MoveResolver: adding mapping from interval %d (%s) to interval %d (%s)", fromInterval.operandNumber, fromInterval.location(), toInterval.operandNumber, toInterval.location()); - } - - assert fromInterval.operand != toInterval.operand : "from and to interval equal: " + fromInterval; - assert Util.archKindsEqual(fromInterval.kind(), toInterval.kind()); - mappingFrom.add(fromInterval); - mappingFromOpr.add(CiValue.IllegalValue); - mappingTo.add(toInterval); - } - - void addMapping(CiValue fromOpr, Interval toInterval) { - if (C1XOptions.TraceLinearScanLevel >= 4) { - TTY.println("MoveResolver: adding mapping from %s to %d (%s)", fromOpr, toInterval.operandNumber, toInterval.location()); - } - assert fromOpr.isConstant() : "only for constants"; - - mappingFrom.add(null); - mappingFromOpr.add(fromOpr); - mappingTo.add(toInterval); - } - - void resolveAndAppendMoves() { - if (hasMappings()) { - resolveMappings(); - } - appendInsertionBuffer(); - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/alloc/OperandPool.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/alloc/OperandPool.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,268 +0,0 @@ -/* - * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.alloc; - -import java.util.*; - -import com.sun.c1x.*; -import com.sun.c1x.ir.*; -import com.sun.cri.ci.*; - -/** - * An ordered, 0-based indexable pool of instruction operands for a method being compiled. - * The physical {@linkplain CiRegister registers} of the platform occupy the front of the - * pool (starting at index 0) followed by {@linkplain CiVariable variable} operands. - * The index of an operand in the pool is its {@linkplain #operandNumber(CiValue) operand number}. - * - * In the original HotSpot C1 source code, this pool corresponds to the - * "flat register file" mentioned in c1_LinearScan.cpp. - * - * @author Doug Simon - */ -public final class OperandPool { - - public static final int INITIAL_VARIABLE_CAPACITY = 20; - - /** - * The physical registers occupying the head of the operand pool. This is the complete - * {@linkplain CiArchitecture#registers register set} of the target architecture, not - * just the allocatable registers. - */ - private final CiRegister[] registers; - - /** - * The variable operands allocated from this pool. The {@linkplain #operandNumber(CiValue) number} - * of the first variable operand in this pool is one greater than the number of the last - * register operand in the pool. - */ - private final ArrayList variables; - - /** - * Map from a {@linkplain CiVariable#index variable index} to the instruction whose result is stored in the denoted variable. - * This map is only populated and used if {@link C1XOptions#DetailedAsserts} is {@code true}. - */ - private final ArrayList variableDefs; - - /** - * The {@linkplain #operandNumber(CiValue) number} of the first variable operand - * {@linkplain #newVariable(CiKind) allocated} from this pool. - */ - private final int firstVariableNumber; - - /** - * Records which variable operands have the {@link VariableFlag#MustBeByteRegister} flag set. - */ - private CiBitMap mustBeByteRegister; - - /** - * Records which variable operands have the {@link VariableFlag#MustStartInMemory} flag set. - */ - private CiBitMap mustStartInMemory; - - /** - * Records which variable operands have the {@link VariableFlag#MustStayInMemory} flag set. - */ - private CiBitMap mustStayInMemory; - - /** - * Flags that can be set for {@linkplain CiValue#isVariable() variable} operands. - */ - public enum VariableFlag { - /** - * Denotes a variable that needs to be assigned a memory location - * at the beginning, but may then be loaded in a register. - */ - MustStartInMemory, - - /** - * Denotes a variable that needs to be assigned a memory location - * at the beginning and never subsequently loaded in a register. - */ - MustStayInMemory, - - /** - * Denotes a variable that must be assigned to a byte-sized register. - */ - MustBeByteRegister; - - public static final VariableFlag[] VALUES = values(); - } - - private static CiBitMap set(CiBitMap map, CiVariable variable) { - if (map == null) { - int length = CiBitMap.roundUpLength(variable.index + 1); - map = new CiBitMap(length); - } else if (map.size() <= variable.index) { - int length = CiBitMap.roundUpLength(variable.index + 1); - map.grow(length); - } - map.set(variable.index); - return map; - } - - private static boolean get(CiBitMap map, CiVariable variable) { - if (map == null || map.size() <= variable.index) { - return false; - } - return map.get(variable.index); - } - - /** - * Creates a new operand pool. - * - * @param target description of the target architecture for a compilation - */ - public OperandPool(CiTarget target) { - CiRegister[] registers = target.arch.registers; - this.firstVariableNumber = registers.length; - this.registers = registers; - variables = new ArrayList(INITIAL_VARIABLE_CAPACITY); - variableDefs = C1XOptions.DetailedAsserts ? new ArrayList(INITIAL_VARIABLE_CAPACITY) : null; - } - - /** - * Creates a new {@linkplain CiVariable variable} operand. - * - * @param kind the kind of the variable - * @return a new variable - */ - public CiVariable newVariable(CiKind kind) { - return newVariable(kind, kind == CiKind.Boolean || kind == CiKind.Byte ? VariableFlag.MustBeByteRegister : null); - } - - /** - * Creates a new {@linkplain CiVariable variable} operand. - * - * @param kind the kind of the variable - * @param flag a flag that is set for the new variable operand (ignored if {@code null}) - * @return a new variable operand - */ - public CiVariable newVariable(CiKind kind, VariableFlag flag) { - assert kind != CiKind.Void; - int varIndex = variables.size(); - CiVariable var = CiVariable.get(kind, varIndex); - if (flag == VariableFlag.MustBeByteRegister) { - mustBeByteRegister = set(mustBeByteRegister, var); - } else if (flag == VariableFlag.MustStartInMemory) { - mustStartInMemory = set(mustStartInMemory, var); - } else if (flag == VariableFlag.MustStayInMemory) { - mustStayInMemory = set(mustStayInMemory, var); - } else { - assert flag == null; - } - variables.add(var); - return var; - } - - /** - * Gets the unique number for an operand contained in this pool. - * - * - * @param operand an operand - * @return the unique number for {@code operand} in the range {@code [0 .. size())} - */ - public int operandNumber(CiValue operand) { - if (operand.isRegister()) { - int number = operand.asRegister().number; - assert number < firstVariableNumber; - return number; - } - assert operand.isVariable(); - return firstVariableNumber + ((CiVariable) operand).index; - } - - /** - * Gets the operand in this pool denoted by a given operand number. - * - * @param operandNumber a value that must be in the range {@code [0 .. size())} - * @return the operand in this pool denoted by {@code operandNumber} - */ - public CiValue operandFor(int operandNumber) { - if (operandNumber < firstVariableNumber) { - assert operandNumber >= 0; - return registers[operandNumber].asValue(); - } - int index = operandNumber - firstVariableNumber; - CiVariable variable = variables.get(index); - assert variable.index == index; - return variable; - } - - /** - * Records that the result of {@code instruction} is stored in {@code result}. - * - * @param result the variable storing the result of {@code instruction} - * @param instruction an instruction that produces a result (i.e. pushes a value to the stack) - */ - public void recordResult(CiVariable result, Value instruction) { - while (variableDefs.size() <= result.index) { - variableDefs.add(null); - } - variableDefs.set(result.index, instruction); - } - - /** - * Gets the instruction whose result is recorded in a given variable. - * - * @param result the variable storing the result of an instruction - * @return the instruction that stores its result in {@code result} - */ - public Value instructionForResult(CiVariable result) { - if (variableDefs.size() > result.index) { - return variableDefs.get(result.index); - } - return null; - } - - public boolean mustStartInMemory(CiVariable operand) { - return get(mustStartInMemory, operand) || get(mustStayInMemory, operand); - } - - public boolean mustStayInMemory(CiVariable operand) { - return get(mustStayInMemory, operand); - } - - public boolean mustBeByteRegister(CiValue operand) { - return get(mustBeByteRegister, (CiVariable) operand); - } - - public void setMustBeByteRegister(CiVariable operand) { - mustBeByteRegister = set(mustBeByteRegister, operand); - } - - /** - * Gets the number of operands in this pool. This value will increase by 1 for - * each new variable operand {@linkplain #newVariable(CiKind) allocated} from this pool. - */ - public int size() { - return firstVariableNumber + variables.size(); - } - - /** - * Gets the highest operand number for a register operand in this pool. This value will - * never change for the lifetime of this pool. - */ - public int maxRegisterNumber() { - return firstVariableNumber - 1; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/alloc/Range.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/alloc/Range.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,119 +0,0 @@ -/* - * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.alloc; - - -/** - * Represents a range of integers from a start (inclusive) to an end (exclusive. - * - * @author Thomas Wuerthinger - */ -public final class Range { - - public static final Range EndMarker = new Range(Integer.MAX_VALUE, Integer.MAX_VALUE, null); - - /** - * The start of the range, inclusive. - */ - public int from; - - /** - * The end of the range, exclusive. - */ - public int to; - - /** - * A link to allow the range to be put into a singly linked list. - */ - public Range next; - - boolean intersects(Range r) { - return intersectsAt(r) != -1; - } - - - /** - * Creates a new range. - * - * @param from the start of the range, inclusive - * @param to the end of the range, exclusive - * @param next link to the next range in a linked list - */ - Range(int from, int to, Range next) { - this.from = from; - this.to = to; - this.next = next; - } - - int intersectsAt(Range r2) { - Range r1 = this; - - assert r2 != null : "null ranges not allowed"; - assert r1 != EndMarker && r2 != EndMarker : "empty ranges not allowed"; - - do { - if (r1.from < r2.from) { - if (r1.to <= r2.from) { - r1 = r1.next; - if (r1 == EndMarker) { - return -1; - } - } else { - return r2.from; - } - } else { - if (r2.from < r1.from) { - if (r2.to <= r1.from) { - r2 = r2.next; - if (r2 == EndMarker) { - return -1; - } - } else { - return r1.from; - } - } else { // r1.from() == r2.from() - if (r1.from == r1.to) { - r1 = r1.next; - if (r1 == EndMarker) { - return -1; - } - } else { - if (r2.from == r2.to) { - r2 = r2.next; - if (r2 == EndMarker) { - return -1; - } - } else { - return r1.from; - } - } - } - } - } while (true); - } - - @Override - public String toString() { - return "[" + from + ", " + to + "]"; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/alloc/RegisterVerifier.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/alloc/RegisterVerifier.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,277 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.alloc; - -import java.util.*; - -import com.sun.c1x.*; -import com.sun.c1x.debug.*; -import com.sun.c1x.lir.*; -import com.sun.c1x.util.*; -import com.sun.cri.ci.*; - -/** - * - * @author Thomas Wuerthinger - */ -final class RegisterVerifier { - - LinearScan allocator; - List workList; // all blocks that must be processed - ArrayMap savedStates; // saved information of previous check - - // simplified access to methods of LinearScan - C1XCompilation compilation() { - return allocator.compilation; - } - - Interval intervalAt(CiValue operand) { - return allocator.intervalFor(operand); - } - - // currently, only registers are processed - int stateSize() { - return allocator.operands.maxRegisterNumber() + 1; - } - - // accessors - Interval[] stateForBlock(LIRBlock block) { - return savedStates.get(block.blockID()); - } - - void setStateForBlock(LIRBlock block, Interval[] savedState) { - savedStates.put(block.blockID(), savedState); - } - - void addToWorkList(LIRBlock block) { - if (!workList.contains(block)) { - workList.add(block); - } - } - - RegisterVerifier(LinearScan allocator) { - this.allocator = allocator; - workList = new ArrayList(16); - this.savedStates = new ArrayMap(); - - } - - void verify(LIRBlock start) { - // setup input registers (method arguments) for first block - Interval[] inputState = new Interval[stateSize()]; - CiCallingConvention args = compilation().frameMap().incomingArguments(); - for (int n = 0; n < args.locations.length; n++) { - CiValue operand = args.locations[n]; - if (operand.isRegister()) { - CiValue reg = operand; - Interval interval = intervalAt(reg); - inputState[reg.asRegister().number] = interval; - } - } - - setStateForBlock(start, inputState); - addToWorkList(start); - - // main loop for verification - do { - LIRBlock block = workList.get(0); - workList.remove(0); - - processBlock(block); - } while (!workList.isEmpty()); - } - - private void processBlock(LIRBlock block) { - if (C1XOptions.TraceLinearScanLevel >= 2) { - TTY.println(); - TTY.println("processBlock B%d", block.blockID()); - } - - // must copy state because it is modified - Interval[] inputState = copy(stateForBlock(block)); - - if (C1XOptions.TraceLinearScanLevel >= 4) { - TTY.println("Input-State of intervals:"); - TTY.print(" "); - for (int i = 0; i < stateSize(); i++) { - if (inputState[i] != null) { - TTY.print(" %4d", inputState[i].operandNumber); - } else { - TTY.print(" __"); - } - } - TTY.println(); - TTY.println(); - } - - // process all operations of the block - processOperations(block.lir(), inputState); - - // iterate all successors - for (LIRBlock succ : block.blockSuccessors()) { - processSuccessor(succ, inputState); - } - } - - private void processSuccessor(LIRBlock block, Interval[] inputState) { - Interval[] savedState = stateForBlock(block); - - if (savedState != null) { - // this block was already processed before. - // check if new inputState is consistent with savedState - - boolean savedStateCorrect = true; - for (int i = 0; i < stateSize(); i++) { - if (inputState[i] != savedState[i]) { - // current inputState and previous savedState assume a different - // interval in this register . assume that this register is invalid - if (savedState[i] != null) { - // invalidate old calculation only if it assumed that - // register was valid. when the register was already invalid, - // then the old calculation was correct. - savedStateCorrect = false; - savedState[i] = null; - - if (C1XOptions.TraceLinearScanLevel >= 4) { - TTY.println("processSuccessor B%d: invalidating slot %d", block.blockID(), i); - } - } - } - } - - if (savedStateCorrect) { - // already processed block with correct inputState - if (C1XOptions.TraceLinearScanLevel >= 2) { - TTY.println("processSuccessor B%d: previous visit already correct", block.blockID()); - } - } else { - // must re-visit this block - if (C1XOptions.TraceLinearScanLevel >= 2) { - TTY.println("processSuccessor B%d: must re-visit because input state changed", block.blockID()); - } - addToWorkList(block); - } - - } else { - // block was not processed before, so set initial inputState - if (C1XOptions.TraceLinearScanLevel >= 2) { - TTY.println("processSuccessor B%d: initial visit", block.blockID()); - } - - setStateForBlock(block, copy(inputState)); - addToWorkList(block); - } - } - - Interval[] copy(Interval[] inputState) { - return inputState.clone(); - } - - void statePut(Interval[] inputState, CiValue location, Interval interval) { - if (location != null && location.isRegister()) { - CiRegister reg = location.asRegister(); - int regNum = reg.number; - if (interval != null) { - if (C1XOptions.TraceLinearScanLevel >= 4) { - TTY.println(" %s = %s", reg, interval.operand); - } - } else if (inputState[regNum] != null) { - if (C1XOptions.TraceLinearScanLevel >= 4) { - TTY.println(" %s = null", reg); - } - } - - inputState[regNum] = interval; - } - } - - boolean checkState(Interval[] inputState, CiValue reg, Interval interval) { - if (reg != null && reg.isRegister()) { - if (inputState[reg.asRegister().number] != interval) { - throw new CiBailout("!! Error in register allocation: register " + reg + " does not contain interval " + interval.operand + " but interval " + inputState[reg.asRegister().number]); - } - } - return true; - } - - void processOperations(LIRList ops, Interval[] inputState) { - // visit all instructions of the block - for (int i = 0; i < ops.length(); i++) { - LIRInstruction op = ops.at(i); - - if (C1XOptions.TraceLinearScanLevel >= 4) { - TTY.println(op.toStringWithIdPrefix()); - } - - // check if input operands are correct - int n = op.operandCount(LIRInstruction.OperandMode.Input); - for (int j = 0; j < n; j++) { - CiValue operand = op.operandAt(LIRInstruction.OperandMode.Input, j); - if (allocator.isProcessed(operand)) { - Interval interval = intervalAt(operand); - if (op.id != -1) { - interval = interval.getSplitChildAtOpId(op.id, LIRInstruction.OperandMode.Input, allocator); - } - - assert checkState(inputState, interval.location(), interval.splitParent()); - } - } - - // invalidate all caller save registers at calls - if (op.hasCall) { - for (CiRegister r : allocator.compilation.registerConfig.getCallerSaveRegisters()) { - statePut(inputState, r.asValue(), null); - } - } - - // set temp operands (some operations use temp operands also as output operands, so can't set them null) - n = op.operandCount(LIRInstruction.OperandMode.Temp); - for (int j = 0; j < n; j++) { - CiValue operand = op.operandAt(LIRInstruction.OperandMode.Temp, j); - if (allocator.isProcessed(operand)) { - Interval interval = intervalAt(operand); - assert interval != null : "Could not find interval for operand " + operand; - if (op.id != -1) { - interval = interval.getSplitChildAtOpId(op.id, LIRInstruction.OperandMode.Temp, allocator); - } - - statePut(inputState, interval.location(), interval.splitParent()); - } - } - - // set output operands - n = op.operandCount(LIRInstruction.OperandMode.Output); - for (int j = 0; j < n; j++) { - CiValue operand = op.operandAt(LIRInstruction.OperandMode.Output, j); - if (allocator.isProcessed(operand)) { - Interval interval = intervalAt(operand); - if (op.id != -1) { - interval = interval.getSplitChildAtOpId(op.id, LIRInstruction.OperandMode.Output, allocator); - } - - statePut(inputState, interval.location(), interval.splitParent()); - } - } - } - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/asm/ExceptionInfo.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/asm/ExceptionInfo.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.asm; - -import com.sun.c1x.lir.*; - -public class ExceptionInfo { - - public final int codeOffset; - public final LIRBlock exceptionEdge; - public final int bci; - - public ExceptionInfo(int pcOffset, LIRBlock exceptionEdge, int bci) { - this.codeOffset = pcOffset; - this.exceptionEdge = exceptionEdge; - this.bci = bci; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/asm/TargetMethodAssembler.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/asm/TargetMethodAssembler.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,200 +0,0 @@ -/* - * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.asm; - -import java.util.*; - -import com.oracle.max.asm.*; -import com.sun.c1x.*; -import com.sun.c1x.debug.*; -import com.sun.c1x.lir.*; -import com.sun.c1x.util.*; -import com.sun.cri.ci.*; -import com.sun.cri.ri.*; - -public class TargetMethodAssembler { - public final AbstractAssembler asm; - public final CiTargetMethod targetMethod; - public List exceptionInfoList; - protected int lastSafepointPos; - - public TargetMethodAssembler(AbstractAssembler asm) { - this.asm = asm; - this.targetMethod = new CiTargetMethod(); - } - - public void setFrameSize(int frameSize) { - targetMethod.setFrameSize(frameSize); - } - - public CiTargetMethod.Mark recordMark(Object id, CiTargetMethod.Mark[] references) { - return targetMethod.recordMark(asm.codeBuffer.position(), id, references); - } - - public void blockComment(String s) { - targetMethod.addAnnotation(new CiTargetMethod.CodeComment(asm.codeBuffer.position(), s)); - } - - public CiTargetMethod finishTargetMethod(Object name, RiRuntime runtime, int registerRestoreEpilogueOffset, boolean isStub) { - // Install code, data and frame size - targetMethod.setTargetCode(asm.codeBuffer.close(false), asm.codeBuffer.position()); - targetMethod.setRegisterRestoreEpilogueOffset(registerRestoreEpilogueOffset); - - // Record exception handlers if they exist - if (exceptionInfoList != null) { - for (ExceptionInfo ei : exceptionInfoList) { - int codeOffset = ei.codeOffset; - targetMethod.recordExceptionHandler(codeOffset, -1, 0, ei.exceptionEdge.blockEntryPco, -1, null); - } - } - - if (C1XOptions.PrintMetrics) { - C1XMetrics.TargetMethods++; - C1XMetrics.CodeBytesEmitted += targetMethod.targetCodeSize(); - C1XMetrics.SafepointsEmitted += targetMethod.safepoints.size(); - C1XMetrics.DirectCallSitesEmitted += targetMethod.directCalls.size(); - C1XMetrics.IndirectCallSitesEmitted += targetMethod.indirectCalls.size(); - C1XMetrics.DataPatches += targetMethod.dataReferences.size(); - C1XMetrics.ExceptionHandlersEmitted += targetMethod.exceptionHandlers.size(); - } - - if (C1XOptions.PrintAssembly && !TTY.isSuppressed() && !isStub) { - Util.printSection("Target Method", Util.SECTION_CHARACTER); - TTY.println("Name: " + name); - TTY.println("Frame size: " + targetMethod.frameSize()); - TTY.println("Register size: " + asm.target.arch.registerReferenceMapBitCount); - - if (C1XOptions.PrintCodeBytes) { - Util.printSection("Code", Util.SUB_SECTION_CHARACTER); - TTY.println("Code: %d bytes", targetMethod.targetCodeSize()); - Util.printBytes(0L, targetMethod.targetCode(), 0, targetMethod.targetCodeSize(), C1XOptions.PrintAssemblyBytesPerLine); - } - - Util.printSection("Disassembly", Util.SUB_SECTION_CHARACTER); - String disassembly = runtime.disassemble(targetMethod); - TTY.println(disassembly); - boolean noDis = disassembly == null || disassembly.length() == 0; - - Util.printSection("Safepoints", Util.SUB_SECTION_CHARACTER); - for (CiTargetMethod.Safepoint x : targetMethod.safepoints) { - TTY.println(x.toString()); - if (noDis && x.debugInfo != null) { - TTY.println(CiUtil.indent(x.debugInfo.toString(), " ")); - } - } - - Util.printSection("Direct Call Sites", Util.SUB_SECTION_CHARACTER); - for (CiTargetMethod.Call x : targetMethod.directCalls) { - TTY.println(x.toString()); - if (noDis && x.debugInfo != null) { - TTY.println(CiUtil.indent(x.debugInfo.toString(), " ")); - } - } - - Util.printSection("Indirect Call Sites", Util.SUB_SECTION_CHARACTER); - for (CiTargetMethod.Call x : targetMethod.indirectCalls) { - TTY.println(x.toString()); - if (noDis && x.debugInfo != null) { - TTY.println(CiUtil.indent(x.debugInfo.toString(), " ")); - } - } - - Util.printSection("Data Patches", Util.SUB_SECTION_CHARACTER); - for (CiTargetMethod.DataPatch x : targetMethod.dataReferences) { - TTY.println(x.toString()); - } - - Util.printSection("Marks", Util.SUB_SECTION_CHARACTER); - for (CiTargetMethod.Mark x : targetMethod.marks) { - TTY.println(x.toString()); - } - - Util.printSection("Exception Handlers", Util.SUB_SECTION_CHARACTER); - for (CiTargetMethod.ExceptionHandler x : targetMethod.exceptionHandlers) { - TTY.println(x.toString()); - } - } - - return targetMethod; - } - - public void recordExceptionHandlers(int pcOffset, LIRDebugInfo info) { - if (info != null) { - if (info.exceptionEdge() != null) { - if (exceptionInfoList == null) { - exceptionInfoList = new ArrayList(4); - } - exceptionInfoList.add(new ExceptionInfo(pcOffset, info.exceptionEdge(), info.state.bci)); - } - } - } - - public void recordImplicitException(int pcOffset, LIRDebugInfo info) { - // record an implicit exception point - if (info != null) { - assert lastSafepointPos < pcOffset; - lastSafepointPos = pcOffset; - targetMethod.recordSafepoint(pcOffset, info.debugInfo()); - assert info.exceptionEdge() == null; - } - } - - public void recordDirectCall(int posBefore, int posAfter, Object target, LIRDebugInfo info) { - CiDebugInfo debugInfo = info != null ? info.debugInfo() : null; - assert lastSafepointPos < posAfter; - lastSafepointPos = posAfter; - targetMethod.recordCall(posBefore, target, debugInfo, true); - } - - public void recordIndirectCall(int posBefore, int posAfter, Object target, LIRDebugInfo info) { - CiDebugInfo debugInfo = info != null ? info.debugInfo() : null; - assert lastSafepointPos < posAfter; - lastSafepointPos = posAfter; - targetMethod.recordCall(posBefore, target, debugInfo, false); - } - - public void recordSafepoint(int pos, LIRDebugInfo info) { - // safepoints always need debug info - CiDebugInfo debugInfo = info.debugInfo(); - assert lastSafepointPos < pos; - lastSafepointPos = pos; - targetMethod.recordSafepoint(pos, debugInfo); - } - - public CiAddress recordDataReferenceInCode(CiConstant data) { - assert data != null; - - int pos = asm.codeBuffer.position(); - - if (C1XOptions.TraceRelocation) { - TTY.print("Data reference in code: pos = %d, data = %s", pos, data.toString()); - } - - targetMethod.recordDataReference(pos, data); - return CiAddress.Placeholder; - } - - public int lastSafepointPos() { - return lastSafepointPos; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/debug/BlockPrinter.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/debug/BlockPrinter.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,123 +0,0 @@ -/* - * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.debug; - -import com.oracle.graal.graph.*; -import com.oracle.max.graal.schedule.*; -import com.sun.c1x.graph.*; -import com.sun.c1x.ir.*; -import com.sun.c1x.util.*; -import com.sun.c1x.value.*; - -/** - * Prints a listing for a {@linkplain Merge block}. - */ -public class BlockPrinter implements BlockClosure { - - private final InstructionPrinter ip; - private final boolean cfgOnly; - - public BlockPrinter(IR ir, InstructionPrinter ip, boolean cfgOnly) { - this.ip = ip; - this.cfgOnly = cfgOnly; - } - - public void apply(Block block) { - if (cfgOnly) { - if (block.getInstructions().size() > 0) { - ip.printInstruction((Instruction) block.getInstructions().get(0)); - } else { - ip.out().println("Empty block"); - } - ip.out().println(); - } else { - printBlock(block); - } - } - - public void printBlock(Block block) { - LogStream out = ip.out(); - out.println(); - - ip.printInstructionListingHeader(); - - for (Node i : block.getInstructions()) { - if (i instanceof Instruction) { - ip.printInstructionListing((Instruction) i); - } - } - out.println(); - - } - - private static void printFrameState(FrameState newFrameState, LogStream out) { - int startPosition = out.position(); - if (newFrameState.stackSize() == 0) { - out.print("empty stack"); - } else { - out.print("stack ["); - int i = 0; - while (i < newFrameState.stackSize()) { - if (i > 0) { - out.print(", "); - } - Value value = newFrameState.stackAt(i); - out.print(i + ":" + Util.valueString(value)); - if (value == null) { - i++; - } else { - i += value.kind.sizeInSlots(); - if (value instanceof Phi) { - Phi phi = (Phi) value; - if (phi.operand() != null) { - out.print(" "); - out.print(phi.operand().toString()); - } - } - } - } - out.print(']'); - } - if (newFrameState.locksSize() != 0) { - // print out the lines on the line below this - // one at the same indentation level. - out.println(); - out.fillTo(startPosition, ' '); - out.print("locks ["); - for (int i = 0; i < newFrameState.locksSize(); i++) { - Value value = newFrameState.lockAt(i); - if (i > 0) { - out.print(", "); - } - out.print(i + ":"); - if (value == null) { - // synchronized methods push null on the lock stack - out.print("this"); - } else { - out.print(Util.valueString(value)); - } - } - out.print("]"); - } - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/debug/CFGPrinter.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/debug/CFGPrinter.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,636 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.debug; - -import java.io.*; -import java.util.*; - -import com.oracle.graal.graph.*; -import com.oracle.max.graal.schedule.*; -import com.sun.c1x.*; -import com.sun.c1x.alloc.*; -import com.sun.c1x.alloc.Interval.*; -import com.sun.c1x.graph.*; -import com.sun.c1x.ir.*; -import com.sun.c1x.lir.*; -import com.sun.c1x.lir.LIRInstruction.*; -import com.sun.c1x.util.*; -import com.sun.c1x.value.*; -import com.sun.cri.ci.*; -import com.sun.cri.ci.CiAddress.*; -import com.sun.cri.ri.*; - -/** - * Utility for printing the control flow graph of a method being compiled by C1X at various compilation phases. - * The output format matches that produced by HotSpot so that it can then be fed to the - * C1 Visualizer. - */ -public class CFGPrinter { - private static final String COLUMN_END = " <|@"; - private static final String HOVER_START = "<@"; - private static final String HOVER_SEP = "|@"; - private static final String HOVER_END = ">@"; - - private static OutputStream cfgFileStream; - - /** - * Gets the output stream on the file "output.cfg" in the current working directory. - * This stream is first opened if necessary. - * - * @return the output stream to "output.cfg" or {@code null} if there was an error opening this file for writing - */ - public static synchronized OutputStream cfgFileStream() { - if (cfgFileStream == null) { - File cfgFile = new File("output.cfg"); - try { - cfgFileStream = new FileOutputStream(cfgFile); - } catch (FileNotFoundException e) { - TTY.println("WARNING: Could not open " + cfgFile.getAbsolutePath()); - } - } - return cfgFileStream; - } - - private final LogStream out; - private final CiTarget target; - - /** - * Creates a control flow graph printer. - * - * @param os where the output generated via this printer shown be written - * @param target the target architecture description - */ - public CFGPrinter(OutputStream os, CiTarget target) { - out = new LogStream(os); - this.target = target; - } - - /** - * Flushes all buffered output to the stream passed to {@link #CFGPrinter(OutputStream, CiTarget)}. - */ - public void flush() { - out.flush(); - } - - private void begin(String string) { - out.println("begin_" + string); - out.adjustIndentation(2); - } - - private void end(String string) { - out.adjustIndentation(-2); - out.println("end_" + string); - } - - /** - * Prints a compilation timestamp for a given method. - * - * @param method the method for which a timestamp will be printed - */ - public void printCompilation(RiMethod method) { - begin("compilation"); - out.print("name \" ").print(CiUtil.format("%H::%n", method, true)).println('"'); - out.print("method \"").print(CiUtil.format("%f %r %H.%n(%p)", method, true)).println('"'); - out.print("date ").println(System.currentTimeMillis()); - end("compilation"); - } - - /** - * Print the details of a given control flow graph block. - * - * @param block the block to print - * @param successors the successor blocks of {@code block} - * @param handlers the exception handler blocks of {@code block} - * @param printHIR if {@code true} the HIR for each instruction in the block will be printed - * @param printLIR if {@code true} the LIR for each instruction in the block will be printed - */ - void printBlock(Block block, List successors, Block handler, boolean printHIR, boolean printLIR) { - begin("block"); - - out.print("name \"B").print(block.blockID()).println('"'); - out.print("from_bci -1"); - out.print("to_bci -1"); - - out.print("predecessors "); - for (Block pred : block.getPredecessors()) { - out.print("\"B").print(pred.blockID()).print("\" "); - } - out.println(); - - out.print("successors "); - for (Block succ : successors) { - out.print("\"B").print(succ.blockID()).print("\" "); - } - out.println(); - - out.print("xhandlers"); - if (handler != null) { - out.print("\"B").print(handler.blockID()).print("\" "); - } - out.println(); - - out.print("flags "); - out.println(); - - out.print("loop_index ").println(-1); - out.print("loop_depth ").println(-1); - - if (printHIR) { - printHIR(block); - } - - // TODO(tw): Add possibility to print LIR. - //if (printLIR) { - // printLIR(block.lirBlock()); - //} - - end("block"); - } - - /** - * Prints the JVM frame state upon entry to a given block. - * - * @param block the block for which the frame state is to be printed - */ - /*private void printState(Block block) { - begin("states"); - - FrameState state = block.stateBefore(); - if (state == null) { - return; - } - int stackSize = state.stackSize(); - if (stackSize > 0) { - begin("stack"); - out.print("size ").println(stackSize); - out.print("method \"").print(CiUtil.toLocation(C1XCompilation.compilation().method, state.bci)).println('"'); - - int i = 0; - while (i < stackSize) { - Value value = state.stackAt(i); - out.disableIndentation(); - out.print(block.stateString(i, value)); - printOperand(value); - out.println(); - out.enableIndentation(); - if (value == null) { - i++; - } else { - i += value.kind.sizeInSlots(); - } - } - end("stack"); - } - - if (state.locksSize() > 0) { - begin("locks"); - out.print("size ").println(state.locksSize()); - out.print("method \"").print(CiUtil.toLocation(C1XCompilation.compilation().method, state.bci)).println('"'); - - for (int i = 0; i < state.locksSize(); ++i) { - Value value = state.lockAt(i); - out.disableIndentation(); - out.print(block.stateString(i, value)); - printOperand(value); - out.println(); - out.enableIndentation(); - } - end("locks"); - } - - begin("locals"); - out.print("size ").println(state.localsSize()); - out.print("method \"").print(CiUtil.toLocation(C1XCompilation.compilation().method, state.bci)).println('"'); - int i = 0; - while (i < state.localsSize()) { - Value value = state.localAt(i); - if (value != null) { - out.disableIndentation(); - out.print(block.stateString(i, value)); - printOperand(value); - out.println(); - out.enableIndentation(); - // also ignore illegal HiWords - i += value.isIllegal() ? 1 : value.kind.sizeInSlots(); - } else { - i++; - } - } - end("locals"); - end("states"); - }*/ - - /** - * Formats a given {@linkplain FrameState JVM frame state} as a multi line string. - */ - private String stateToString(FrameState state, CFGOperandFormatter operandFmt) { - if (state == null) { - return null; - } - - StringBuilder buf = new StringBuilder(); - buf.append(CiUtil.toLocation(C1XCompilation.compilation().method, state.bci)); - buf.append('\n'); - if (state.stackSize() > 0) { - int i = 0; - buf.append("stack: "); - while (i < state.stackSize()) { - if (i == 0) { - buf.append(' '); - } - Value value = state.stackAt(i); - buf.append(stateValueToString(value, operandFmt)).append(' '); - i++; - } - buf.append("\n"); - } - - if (state.locksSize() > 0) { - buf.append("locks: "); - for (int i = 0; i < state.locksSize(); ++i) { - if (i == 0) { - buf.append(' '); - } - Value value = state.lockAt(i); - buf.append(stateValueToString(value, operandFmt)).append(' '); - } - buf.append("\n"); - } - - buf.append("locals: "); - int i = 0; - while (i < state.localsSize()) { - if (i == 0) { - buf.append(' '); - } - Value value = state.localAt(i); - buf.append(stateValueToString(value, operandFmt)).append(' '); - i++; - } - buf.append("\n"); - return buf.toString(); - } - - private String stateValueToString(Value value, OperandFormatter operandFmt) { - if (operandFmt == null) { - return Util.valueString(value); - } - if (value == null) { - return "-"; - } - return operandFmt.format(value.operand()); - } - - private String stateValueToString(CiValue value, OperandFormatter operandFmt) { - if (value == null) { - return "-"; - } - return operandFmt.format(value); - } - - /** - * Formats a given {@linkplain FrameState JVM frame state} as a multi line string. - */ - private String debugInfoToString(CiDebugInfo info, CFGOperandFormatter operandFmt) { - if (info == null) { - return null; - } - StringBuilder sb = new StringBuilder(); - - - if (info.hasRegisterRefMap()) { - sb.append("reg-ref-map:"); - C1XCompilation compilation = C1XCompilation.compilation(); - CiArchitecture arch = compilation == null ? null : compilation.target.arch; - for (int reg = info.registerRefMap.nextSetBit(0); reg >= 0; reg = info.registerRefMap.nextSetBit(reg + 1)) { - sb.append(' ').append(arch == null ? "reg" + reg : arch.registers[reg]); - } - sb.append("\n"); - } - if (info.hasStackRefMap()) { - sb.append("frame-ref-map:"); - CiBitMap bm = info.frameRefMap; - for (int i = bm.nextSetBit(0); i >= 0; i = bm.nextSetBit(i + 1)) { - sb.append(' ').append(CiStackSlot.get(CiKind.Object, i)); - } - sb.append("\n"); - } - if (info.codePos != null) { - sb.append(stateToString(info.codePos, operandFmt)); - } - return sb.toString(); - } - - /** - * Formats a given {@linkplain FrameState JVM frame state} as a multi line string. - */ - private String stateToString(CiCodePos codePos, CFGOperandFormatter operandFmt) { - if (codePos == null) { - return null; - } - - StringBuilder buf = new StringBuilder(); - - do { - buf.append(CiUtil.toLocation(codePos.method, codePos.bci)); - buf.append('\n'); - if (codePos instanceof CiFrame) { - CiFrame frame = (CiFrame) codePos; - if (frame.numStack > 0) { - int i = 0; - buf.append("stack: "); - while (i < frame.numStack) { - if (i == 0) { - buf.append(' '); - } - CiValue value = frame.getStackValue(i); - buf.append(stateValueToString(value, operandFmt)).append(' '); - i++; - } - buf.append("\n"); - } - - if (frame.numLocks > 0) { - buf.append("locks: "); - for (int i = 0; i < frame.numLocks; ++i) { - if (i == 0) { - buf.append(' '); - } - CiValue value = frame.getLockValue(i); - buf.append(stateValueToString(value, operandFmt)).append(' '); - } - buf.append("\n"); - } - - buf.append("locals: "); - int i = 0; - while (i < frame.numLocals) { - if (i == 0) { - buf.append(' '); - } - CiValue value = frame.getLocalValue(i); - buf.append(stateValueToString(value, operandFmt)).append(' '); - i++; - } - buf.append("\n"); - } - codePos = codePos.caller; - } while (codePos != null); - return buf.toString(); - } - - /** - * Prints the HIR for each instruction in a given block. - * - * @param block - */ - private void printHIR(Block block) { - begin("IR"); - out.println("HIR"); - out.disableIndentation(); - for (Node i : block.getInstructions()) { - if (i instanceof Instruction) { - printInstructionHIR((Instruction) i); - } - } - out.enableIndentation(); - end("IR"); - } - - /** - * Formats LIR operands as expected by the C1 Visualizer. - */ - public static class CFGOperandFormatter extends OperandFormatter { - /** - * The textual delimiters used for an operand depend on the context in which it is being - * printed. When printed as part of a frame state or as the result operand in a HIR node listing, - * it is enclosed in double-quotes (i.e. {@code "}'s). - */ - public final boolean asStateOrHIROperandResult; - - public CFGOperandFormatter(boolean asStateOrHIROperandResult) { - this.asStateOrHIROperandResult = asStateOrHIROperandResult; - } - - @Override - public String format(CiValue operand) { - if (operand.isLegal()) { - String op; - if (operand.isVariableOrRegister() || operand.isStackSlot()) { - op = operand.name(); - } else if (operand.isConstant()) { - CiConstant constant = (CiConstant) operand; - op = operand.kind.javaName + ":" + operand.kind.format(constant.boxedValue()); - } else if (operand.isAddress()) { - CiAddress address = (CiAddress) operand; - op = "Base:" + format(address.base); - if (!address.index.isIllegal()) { - op += " Index:" + format(address.index); - } - if (address.scale != Scale.Times1) { - op += " * " + address.scale.value; - } - op += " Disp:" + address.displacement; - } else { - assert operand.isIllegal(); - op = "-"; - } - if (operand.kind != CiKind.Illegal) { - op += "|" + operand.kind.typeChar; - } - if (asStateOrHIROperandResult) { - op = " \"" + op.replace('"', '\'') + "\" "; - } - return op; - } - return ""; - } - } - - /** - * Prints the LIR for each instruction in a given block. - * - * @param block the block to print - */ - private void printLIR(LIRBlock block) { - LIRList lir = block.lir(); - if (lir != null) { - begin("IR"); - out.println("LIR"); - for (int i = 0; i < lir.length(); i++) { - LIRInstruction inst = lir.at(i); - out.printf("nr %4d ", inst.id).print(COLUMN_END); - - if (inst.info != null) { - int level = out.indentationLevel(); - out.adjustIndentation(-level); - String state; - if (inst.info.debugInfo != null) { - // Use register-allocator output if available - state = debugInfoToString(inst.info.debugInfo, new CFGOperandFormatter(false)); - } else { - state = stateToString(inst.info.state, new CFGOperandFormatter(false)); - } - if (state != null) { - out.print(" st ").print(HOVER_START).print("st").print(HOVER_SEP).print(state).print(HOVER_END).print(COLUMN_END); - } - out.adjustIndentation(level); - } - - out.print(" instruction ").print(inst.toString(new CFGOperandFormatter(false))).print(COLUMN_END); - out.println(COLUMN_END); - } - end("IR"); - } - } - - private void printOperand(Value i) { - if (i != null && i.operand().isLegal()) { - out.print(new CFGOperandFormatter(true).format(i.operand())); - } - } - - /** - * Prints the HIR for a given instruction. - * - * @param i the instruction for which HIR will be printed - */ - private void printInstructionHIR(Instruction i) { - out.print("bci ").print(-1).println(COLUMN_END); - if (i.operand().isLegal()) { - out.print("result ").print(new CFGOperandFormatter(false).format(i.operand())).println(COLUMN_END); - } - out.print("tid ").print(i).println(COLUMN_END); - - String state = stateToString(i.stateAfter(), null); - if (state != null) { - out.print("st ").print(HOVER_START).print("st").print(HOVER_SEP).print(state).print(HOVER_END).println(COLUMN_END); - } - - out.print("instruction "); - i.print(out); - out.print(COLUMN_END).print(' ').println(COLUMN_END); - } - - /** - * Prints the control flow graph denoted by a given block map. - * - * @param blockMap a data structure describing the blocks in a method and how they are connected - * @param codeSize the bytecode size of the method from which {@code blockMap} was produced - * @param label a label describing the compilation phase that produced the control flow graph - * @param printHIR if {@code true} the HIR for each instruction in the block will be printed - * @param printLIR if {@code true} the LIR for each instruction in the block will be printed - */ - public void printCFG(RiMethod method, BlockMap blockMap, int codeSize, String label, boolean printHIR, boolean printLIR) { - begin("cfg"); - out.print("name \"").print(label).println('"'); - for (BlockMap.Block block : blockMap.blocks) { - begin("block"); - blockMap.printBlock(block, out); - end("block"); - } - end("cfg"); - } - - /** - * Prints the control flow graph rooted at a given block. - * - * @param startBlock the entry block of the control flow graph to be printed - * @param label a label describing the compilation phase that produced the control flow graph - * @param printHIR if {@code true} the HIR for each instruction in the block will be printed - * @param printLIR if {@code true} the LIR for each instruction in the block will be printed - */ - public void printCFG(Block startBlock, String label, final boolean printHIR, final boolean printLIR) { - begin("cfg"); - out.print("name \"").print(label).println('"'); - startBlock.iteratePreOrder(new BlockClosure() { - public void apply(Block block) { - List successors = block.getSuccessors(); - printBlock(block, successors, null, printHIR, printLIR); - } - }); - end("cfg"); - } - - public void printIntervals(LinearScan allocator, Interval[] intervals, String name) { - begin("intervals"); - out.println(String.format("name \"%s\"", name)); - - for (Interval interval : intervals) { - if (interval != null) { - printInterval(allocator, interval); - } - } - - end("intervals"); - } - - private void printInterval(LinearScan allocator, Interval interval) { - out.printf("%d %s ", interval.operandNumber, (interval.operand.isRegister() ? "fixed" : interval.kind().name())); - if (interval.operand.isRegister()) { - out.printf("\"[%s|%c]\"", interval.operand.name(), interval.operand.kind.typeChar); - } else { - if (interval.location() != null) { - out.printf("\"[%s|%c]\"", interval.location().name(), interval.location().kind.typeChar); - } - } - - Interval hint = interval.locationHint(false, allocator); - out.printf("%d %d ", interval.splitParent().operandNumber, hint != null ? hint.operandNumber : -1); - - // print ranges - Range cur = interval.first(); - while (cur != Range.EndMarker) { - out.printf("[%d, %d[", cur.from, cur.to); - cur = cur.next; - assert cur != null : "range list not closed with range sentinel"; - } - - // print use positions - int prev = 0; - UsePosList usePosList = interval.usePosList(); - for (int i = usePosList.size() - 1; i >= 0; --i) { - assert prev < usePosList.usePos(i) : "use positions not sorted"; - out.printf("%d %s ", usePosList.usePos(i), usePosList.registerPriority(i)); - prev = usePosList.usePos(i); - } - - out.printf(" \"%s\"", interval.spillState()); - out.println(); - } - - public void printMachineCode(String code, String label) { - if (code.length() == 0) { - return; - } - if (label != null) { - begin("cfg"); - out.print("name \"").print(label).println('"'); - end("cfg"); - } - begin("nmethod"); - out.print(code); - out.println(" <|@"); - end("nmethod"); - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/debug/CFGPrinterObserver.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/debug/CFGPrinterObserver.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,120 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.debug; - -import java.io.*; - -import com.sun.c1x.*; -import com.sun.c1x.observer.*; -import com.sun.cri.ri.*; - -/** - * Observes compilation events and uses {@link CFGPrinter} to produce a control flow graph for the C1 Visualizer. - * - * @author Peter Hofer - */ -public class CFGPrinterObserver implements CompilationObserver { - - private C1XCompilation currentCompilation; - private CFGPrinter cfgPrinter; - private ByteArrayOutputStream buffer = null; - private final OutputStream stream; - - public CFGPrinterObserver() { - this(CFGPrinter.cfgFileStream()); - } - - public CFGPrinterObserver(OutputStream stream) { - this.stream = stream; - } - - @Override - public void compilationStarted(CompilationEvent event) { - // Supports only one compilation at the same time - assert currentCompilation == null; - - currentCompilation = event.getCompilation(); - if (buffer == null) { - buffer = new ByteArrayOutputStream(); - } - cfgPrinter = new CFGPrinter(buffer, currentCompilation.target); - cfgPrinter.printCompilation(currentCompilation.method); - } - - @Override - public void compilationEvent(CompilationEvent event) { - assert currentCompilation == event.getCompilation(); - - String label = event.getLabel(); - - if (event.getAllocator() != null && event.getIntervals() != null) { - cfgPrinter.printIntervals(event.getAllocator(), event.getIntervals(), label); - } - - boolean cfgprinted = false; - - if (event.getBlockMap() != null && event.getCodeSize() >= 0) { - cfgPrinter.printCFG(event.getMethod(), event.getBlockMap(), event.getCodeSize(), label, event.isHIRValid(), event.isLIRValid()); - cfgprinted = true; - } - - // TODO fix that when schedule is here (startBlock : Instruction->Block) - /*if (event.getStartBlock() != null) { - cfgPrinter.printCFG((BlockBegin) event.getStartBlock(), label, event.isHIRValid(), event.isLIRValid()); - cfgprinted = true; - }*/ - - if (event.getTargetMethod() != null) { - if (cfgprinted) { - // Avoid duplicate "cfg" section - label = null; - } - - RiRuntime runtime = event.getCompilation().runtime; - cfgPrinter.printMachineCode(runtime.disassemble(event.getTargetMethod()), label); - } - } - - @Override - public void compilationFinished(CompilationEvent event) { - assert currentCompilation == event.getCompilation(); - - cfgPrinter.flush(); - - if (stream != null) { - synchronized (stream) { - try { - stream.write(buffer.toByteArray()); - stream.flush(); - } catch (IOException e) { - TTY.println("WARNING: Error writing CFGPrinter output for %s: %s", event.getMethod(), e); - } - } - } - - buffer.reset(); - cfgPrinter = null; - currentCompilation = null; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/debug/GraphvizPrinterObserver.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/debug/GraphvizPrinterObserver.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,110 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.debug; - -import java.io.*; -import java.util.regex.*; - -import com.oracle.graal.graph.*; -import com.oracle.graal.graph.vis.*; -import com.sun.c1x.*; -import com.sun.c1x.ir.*; -import com.sun.c1x.observer.*; -import com.sun.c1x.value.*; - -/** - * Observes compilation events and uses {@link GraphvizPrinter} to produce a control flow graph in the DOT language - * which can be visualized with Graphviz. - * - * @author Peter Hofer - */ -public class GraphvizPrinterObserver implements CompilationObserver { - - private static final Pattern INVALID_CHAR = Pattern.compile("[^A-Za-z0-9_.-]"); - - private final boolean pdf; - private int n; - - public GraphvizPrinterObserver(boolean pdf) { - this.pdf = pdf; - } - - public void compilationStarted(CompilationEvent event) { - n = 0; - } - - public void compilationFinished(CompilationEvent event) { - } - - public void compilationEvent(CompilationEvent event) { - if (event.getGraph() != null && !TTY.isSuppressed()) { - Graph graph = event.getGraph(); - - String name = event.getMethod().holder().name(); - name = name.substring(1, name.length() - 1).replace('/', '.'); - name = name + "." + event.getMethod().name(); - - String filename = name + "_" + (n++) + "_" + event.getLabel(); - filename = INVALID_CHAR.matcher(filename).replaceAll("_"); - - OutputStream out = null; - try { - if (pdf) { - ByteArrayOutputStream buffer = new ByteArrayOutputStream(); - printGraph(graph, name, buffer); - - out = new FileOutputStream(filename + ".pdf"); - GraphvizRunner.process(GraphvizRunner.DOT_LAYOUT, new ByteArrayInputStream(buffer.toByteArray()), out, "pdf"); - } else { - out = new FileOutputStream(filename + ".gv"); - - printGraph(graph, name, out); - } - } catch (IOException e) { - e.printStackTrace(); - } finally { - if (out != null) { - try { - out.close(); - } catch (IOException e) { - } - } - } - } - } - - private static void printGraph(Graph graph, String name, OutputStream buffer) { - GraphvizPrinter printer = new GraphvizPrinter(buffer); - if (C1XOptions.OmitDOTFrameStates) { - printer.addOmittedClass(FrameState.class); - } - printer.addClassColor(StartNode.class, "snow3"); - printer.addClassColor(LoopBegin.class, "skyblue"); - printer.addClassColor(LoopEnd.class, "skyblue3"); - printer.addClassColor(Unwind.class, "red"); - printer.addClassColor(Return.class, "indianred1"); - printer.begin(name); - printer.print(graph, true); - printer.end(); - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/debug/IdealGraphPrinter.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/debug/IdealGraphPrinter.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,277 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.debug; - -import java.io.*; -import java.util.*; -import java.util.Map.*; - -import com.oracle.graal.graph.*; -import com.oracle.max.graal.schedule.*; -import com.sun.c1x.ir.*; - -/** - * Generates a representation of {@link Graph Graphs} that can be visualized and inspected with the Ideal Graph Visualizer. - */ -public class IdealGraphPrinter { - - private static class Edge { - final int from; - final int to; - final int fromIndex; - final int toIndex; - - Edge(int from, int fromIndex, int to, int toIndex) { - this.from = from; - this.fromIndex = fromIndex; - this.to = to; - this.toIndex = toIndex; - } - } - - private final HashSet> omittedClasses = new HashSet>(); - private final PrintStream stream; - private final List noBlockNodes = new LinkedList(); - - /** - * Creates a new {@link IdealGraphPrinter} that writes to the specified output stream. - */ - public IdealGraphPrinter(OutputStream stream) { - this.stream = new PrintStream(stream); - } - - /** - * Adds a node class that is omitted in the output. - */ - public void addOmittedClass(Class clazz) { - omittedClasses.add(clazz); - } - - /** - * Flushes any buffered output. - */ - public void flush() { - stream.flush(); - } - - /** - * Starts a new graph document. - */ - public void begin() { - stream.println(""); - } - - /** - * Starts a new group of graphs with the given name, short name and method byte code index (BCI) as properties. - */ - public void beginGroup(String name, String shortName, int bci) { - stream.println(""); - stream.printf("

%s

%n", escape(name)); - stream.printf(" %n", escape(name), escape(shortName), bci); - } - - /** - * Ends the current group. - */ - public void endGroup() { - stream.println(""); - } - - /** - * Finishes the graph document and flushes the output stream. - */ - public void end() { - stream.println(""); - flush(); - } - - /** - * Prints an entire {@link Graph} with the specified title, optionally using short names for nodes. - */ - public void print(Graph graph, String title, boolean shortNames) { - stream.printf(" %n", escape(title)); - - Schedule schedule = null; - try { - schedule = new Schedule(graph); - } catch (Throwable t) { - // nothing to do here... - } - - stream.println(" "); - List edges = printNodes(graph.getNodes(), shortNames, schedule == null ? null : schedule.getNodeToBlock()); - stream.println(" "); - - stream.println(" "); - for (Edge edge : edges) { - printEdge(edge); - } - stream.println(" "); - - stream.println(" "); - if (schedule != null) { - for (Block block : schedule.getBlocks()) { - printBlock(graph, block); - } - printNoBlock(); - } - stream.println(" "); - - stream.println(" "); - } - - private List printNodes(Collection nodes, boolean shortNames, NodeMap nodeToBlock) { - ArrayList edges = new ArrayList(); - - for (Node node : nodes) { - if (node == Node.Null || omittedClasses.contains(node.getClass())) { - continue; - } - - stream.printf(" %n", node.id()); - stream.printf("

%d

%n", node.id()); - - Map props = node.getDebugProperties(); - if (!props.containsKey("name") || props.get("name").toString().trim().length() == 0) { - String name; - if (shortNames) { - name = node.shortName(); - } else { - name = node.toString(); - } - stream.printf("

%s

%n", escape(name)); - } - if (nodeToBlock != null) { - Block block = nodeToBlock.get(node); - if (block != null) { - stream.printf("

%d

%n", block.blockID()); - } else { - stream.printf("

noBlock

%n"); - noBlockNodes.add(node); - } - } - for (Entry entry : props.entrySet()) { - String key = entry.getKey().toString(); - String value = entry.getValue().toString(); - stream.printf("

%s

%n", escape(key), escape(value)); - } - - stream.println("
"); - - // successors - int fromIndex = 0; - for (Node successor : node.successors()) { - if (successor != Node.Null && !omittedClasses.contains(successor.getClass())) { - edges.add(new Edge(node.id(), fromIndex, successor.id(), 0)); - } - fromIndex++; - } - - // inputs - int toIndex = 1; - for (Node input : node.inputs()) { - if (input != Node.Null && !omittedClasses.contains(input.getClass())) { - edges.add(new Edge(input.id(), input.successors().size(), node.id(), toIndex)); - } - toIndex++; - } - } - - return edges; - } - - private void printEdge(Edge edge) { - stream.printf(" %n", edge.from, edge.fromIndex, edge.to, edge.toIndex); - } - - private void printBlock(Graph graph, Block block) { - stream.printf(" %n", block.blockID()); - stream.printf(" %n"); - for (Block sux : block.getSuccessors()) { - if (sux.firstNode() instanceof LoopBegin && block.lastNode() instanceof LoopEnd) { - // Skip back edges. - } else { - stream.printf(" %n", sux.blockID()); - } - } - stream.printf(" %n"); - stream.printf(" %n"); - - ArrayList nodes = new ArrayList(block.getInstructions()); - // if this is the first block: add all locals to this block - if (nodes.get(0) == graph.start()) { - for (Node node : graph.getNodes()) { - if (node instanceof Local) { - nodes.add(node); - } - } - } - // add all framestates and phis to their blocks - for (Node node : block.getInstructions()) { - if (node instanceof Instruction && ((Instruction) node).stateAfter() != null) { - nodes.add(((Instruction) node).stateAfter()); - } - if (node instanceof Merge) { - Merge merge = (Merge) node; - if (merge.stateBefore() != null) { - nodes.add(merge.stateBefore()); - } - for (Node usage : merge.usages()) { - if (usage instanceof Phi) { - nodes.add(usage); - } - } - } - } - - for (Node node : nodes) { - if (!omittedClasses.contains(node.getClass())) { - stream.printf(" %n", node.id()); - } - } - stream.printf(" %n"); - stream.printf(" %n", block.blockID()); - } - - private void printNoBlock() { - if (!noBlockNodes.isEmpty()) { - stream.printf(" %n"); - stream.printf(" %n"); - for (Node node : noBlockNodes) { - stream.printf(" %n", node.id()); - } - stream.printf(" %n"); - stream.printf(" %n"); - } - } - - private String escape(String s) { - s = s.replace("&", "&"); - s = s.replace("<", "<"); - s = s.replace(">", ">"); - s = s.replace("\"", """); - s = s.replace("'", "'"); - return s; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/debug/IdealGraphPrinterObserver.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/debug/IdealGraphPrinterObserver.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,171 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.debug; - -import java.io.*; -import java.net.*; -import java.util.regex.*; - -import com.oracle.graal.graph.*; -import com.sun.c1x.*; -import com.sun.c1x.observer.*; -import com.sun.c1x.value.*; - -/** - * Observes compilation events and uses {@link IdealGraphPrinter} to generate a graph representation that can be - * inspected with the Ideal Graph Visualizer. - * - * @author Peter Hofer - */ -public class IdealGraphPrinterObserver implements CompilationObserver { - - private static final Pattern INVALID_CHAR = Pattern.compile("[^A-Za-z0-9_.-]"); - - private final String host; - private final int port; - - private IdealGraphPrinter printer; - private OutputStream stream; - private Socket socket; - - /** - * Creates a new {@link IdealGraphPrinterObserver} that writes output to a file named after the compiled method. - */ - public IdealGraphPrinterObserver() { - this(null, -1); - } - - /** - * Creates a new {@link IdealGraphPrinterObserver} that sends output to a remove IdealGraphVisualizer instance. - */ - public IdealGraphPrinterObserver(String host, int port) { - this.host = host; - this.port = port; - } - - @Override - public void compilationStarted(CompilationEvent event) { - assert (stream == null && printer == null); - - if (!TTY.isSuppressed()) { - String name = event.getMethod().holder().name(); - name = name.substring(1, name.length() - 1).replace('/', '.'); - name = name + "." + event.getMethod().name(); - - if (host != null) { - openNetworkPrinter(name); - } else { - openFilePrinter(name); - } - } - } - - private void openFilePrinter(String name) { - String filename = name + ".igv.xml"; - filename = INVALID_CHAR.matcher(filename).replaceAll("_"); - - try { - stream = new FileOutputStream(filename); - printer = new IdealGraphPrinter(stream); - if (C1XOptions.OmitDOTFrameStates) { - printer.addOmittedClass(FrameState.class); - } - printer.begin(); - printer.beginGroup(name, name, -1); - } catch (IOException e) { - e.printStackTrace(); - } - } - - private void openNetworkPrinter(String name) { - try { - socket = new Socket(host, port); - if (socket.getInputStream().read() == 'y') { - stream = socket.getOutputStream(); - } else { - // server currently does not accept any input - socket.close(); - socket = null; - return; - } - - printer = new IdealGraphPrinter(stream); - if (C1XOptions.OmitDOTFrameStates) { - printer.addOmittedClass(FrameState.class); - } - printer.begin(); - printer.beginGroup(name, name, -1); - printer.flush(); - if (socket.getInputStream().read() != 'y') { - // server declines input for this method - socket.close(); - socket = null; - stream = null; - printer = null; - } - } catch (IOException e) { - e.printStackTrace(); - - if (socket != null) { - try { - socket.close(); - } catch (IOException ioe) { - } - socket = null; - } - stream = null; - printer = null; - } - } - - @Override - public void compilationEvent(CompilationEvent event) { - if (printer != null && event.getGraph() != null) { - Graph graph = event.getGraph(); - printer.print(graph, event.getLabel(), true); - } - } - - @Override - public void compilationFinished(CompilationEvent event) { - if (printer != null) { - try { - printer.endGroup(); - printer.end(); - - if (socket != null) { - socket.close(); // also closes stream - } else { - stream.close(); - } - } catch (IOException e) { - e.printStackTrace(); - } finally { - printer = null; - stream = null; - socket = null; - } - } - } - -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/debug/InstructionPrinter.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/debug/InstructionPrinter.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,150 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.debug; - -import static com.sun.c1x.debug.InstructionPrinter.InstructionLineColumn.*; - -import com.sun.c1x.ir.*; - -/** - * A {@link ValueVisitor} for {@linkplain #printInstruction(Value) printing} - * an {@link Instruction} as an expression or statement. - * - * @author Doug Simon - */ -public class InstructionPrinter { - - - /** - * The columns printed in a tabulated instruction - * {@linkplain InstructionPrinter#printInstructionListing(Value) listing}. - */ - public enum InstructionLineColumn { - /** - * The instruction's bytecode index. - */ - BCI(2, "bci"), - - /** - * The instruction's use count. - */ - USE(7, "use"), - - /** - * The instruction as a {@linkplain com.sun.c1x.util.Util#valueString(com.sun.c1x.ir.Value) value}. - */ - VALUE(12, "tid"), - - /** - * The instruction formatted as an expression or statement. - */ - INSTRUCTION(19, "instr"), - - END(60, ""); - - final int position; - final String label; - - private InstructionLineColumn(int position, String label) { - this.position = position; - this.label = label; - } - - /** - * Prints this column's label to a given stream after padding the stream with '_' characters - * until its {@linkplain LogStream#position() position} is equal to this column's position. - * @param out the print stream - */ - public void printLabel(LogStream out) { - out.fillTo(position + out.indentationLevel(), '_'); - out.print(label); - } - - /** - * Prints space characters to a given stream until its {@linkplain LogStream#position() position} - * is equal to this column's position. - * @param out the print stream - */ - public void advance(LogStream out) { - out.fillTo(position + out.indentationLevel(), ' '); - } - } - - private final LogStream out; - - public InstructionPrinter(LogStream out) { - this.out = out; - } - - public LogStream out() { - return out; - } - - /** - * Prints a given instruction as an expression or statement. - * - * @param instruction the instruction to print - */ - public void printInstruction(Value instruction) { - instruction.print(out); - } - - - /** - * Prints a header for the tabulated data printed by {@link #printInstructionListing(Value)}. - */ - public void printInstructionListingHeader() { - BCI.printLabel(out); - USE.printLabel(out); - VALUE.printLabel(out); - INSTRUCTION.printLabel(out); - END.printLabel(out); - out.println(); - } - - /** - * Prints an instruction listing on one line. The instruction listing is composed of the - * columns specified by {@link InstructionLineColumn}. - * - * @param instruction the instruction to print - */ - public void printInstructionListing(Value instruction) { - int indentation = out.indentationLevel(); - out.fillTo(BCI.position + indentation, ' '). - print(0). - fillTo(USE.position + indentation, ' '). - print("0"). - fillTo(VALUE.position + indentation, ' '). - print(instruction). - fillTo(INSTRUCTION.position + indentation, ' '); - printInstruction(instruction); - String flags = instruction.flagsToString(); - if (!flags.isEmpty()) { - out.print(" [flags: " + flags + "]"); - } - if (instruction instanceof StateSplit) { - out.print(" [state: " + ((StateSplit) instruction).stateAfter() + "]"); - } - out.println(); - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/debug/LogStream.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/debug/LogStream.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,493 +0,0 @@ -/* - * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.debug; - -import java.io.*; - -import com.sun.c1x.ir.*; -import com.sun.c1x.util.*; - -/** - * A utility for printing compiler debug and informational output to an output stream. - * - * A {@link LogStream} instance maintains an internal buffer that is flushed to the underlying - * output stream every time one of the {@code println} methods is invoked, or a newline character - * ({@code '\n'}) is written. - * - * All of the {@code print} and {@code println} methods return the {code LogStream} instance - * on which they were invoked. This allows chaining of these calls to mitigate use of String - * concatenation by the caller. - * - * A {@code LogStream} maintains a current {@linkplain #indentationLevel() indentation} level. - * Each line of output written to this stream has {@code n} spaces prefixed to it where - * {@code n} is the value that would be returned by {@link #indentationLevel()} when the first - * character of a new line is written. - * - * A {@code LogStream} maintains a current {@linkplain #position() position} for the current - * line being written. This position can be advanced to a specified position by - * {@linkplain #fillTo(int, char) filling} this stream with a given character. - * - * @author Doug Simon - */ -public class LogStream { - - /** - * Null output stream that simply swallows any output sent to it. - */ - public static final LogStream SINK = new LogStream(); - - private LogStream() { - this.ps = null; - this.lineBuffer = null; - } - - /** - * The output stream to which this log stream writes. - */ - private final PrintStream ps; - - private final StringBuilder lineBuffer; - private int indentationLevel; - private char indentation = ' '; - private boolean indentationDisabled; - - /** - * The system dependent line separator. - */ - public static final String LINE_SEPARATOR = System.getProperty("line.separator"); - - /** - * Creates a new log stream. - * - * @param os the underlying output stream to which prints are sent - */ - public LogStream(OutputStream os) { - ps = os instanceof PrintStream ? (PrintStream) os : new PrintStream(os); - lineBuffer = new StringBuilder(100); - } - - /** - * Creates a new log stream that shares the same {@linkplain #ps output stream} as a given {@link LogStream}. - * - * @param log a LogStream whose output stream is shared with this one - */ - public LogStream(LogStream log) { - ps = log.ps; - lineBuffer = new StringBuilder(100); - } - - /** - * Prepends {@link #indentation} to the current output line until its write position is equal to the - * current {@linkplain #indentationLevel()} level. - */ - private void indent() { - if (ps != null) { - if (!indentationDisabled && indentationLevel != 0) { - while (lineBuffer.length() < indentationLevel) { - lineBuffer.append(indentation); - } - } - } - } - - private LogStream flushLine(boolean withNewline) { - if (ps != null) { - if (withNewline) { - lineBuffer.append(LINE_SEPARATOR); - } else { - assert lineBuffer.indexOf(LINE_SEPARATOR, lineBuffer.length() - LINE_SEPARATOR.length()) != -1; - } - ps.print(lineBuffer.toString()); - ps.flush(); - lineBuffer.setLength(0); - } - return this; - } - - /** - * Flushes the stream. This is done by terminating the current line if it is not at position 0 - * and then flushing the underlying output stream. - */ - public void flush() { - if (ps != null) { - if (lineBuffer.length() != 0) { - flushLine(true); - } - ps.flush(); - } - } - - /** - * Gets the current column position of this log stream. - * - * @return the current column position of this log stream - */ - public int position() { - return lineBuffer == null ? 0 : lineBuffer.length(); - - } - - /** - * Gets the current indentation level for this log stream. - * - * @return the current indentation level for this log stream. - */ - public int indentationLevel() { - return indentationLevel; - } - - /** - * Adjusts the current indentation level of this log stream. - * - * @param delta - */ - public void adjustIndentation(int delta) { - if (delta < 0) { - indentationLevel = Math.max(0, indentationLevel + delta); - } else { - indentationLevel += delta; - } - } - - /** - * Gets the current indentation character of this log stream. - */ - public char indentation() { - return indentation; - } - - public void disableIndentation() { - indentationDisabled = true; - } - - public void enableIndentation() { - indentationDisabled = false; - } - - /** - * Sets the character used for indentation. - */ - public void setIndentation(char c) { - indentation = c; - } - - /** - * Advances this stream's {@linkplain #position() position} to a given position by - * repeatedly appending a given character as necessary. - * - * @param position the position to which this stream's position will be advanced - * @param filler the character used to pad the stream - */ - public LogStream fillTo(int position, char filler) { - if (ps != null) { - indent(); - while (lineBuffer.length() < position) { - lineBuffer.append(filler); - } - } - return this; - } - - /** - * Writes a boolean value to this stream as {@code "true"} or {@code "false"}. - * - * @param b the value to be printed - * @return this {@link LogStream} instance - */ - public LogStream print(boolean b) { - if (ps != null) { - indent(); - lineBuffer.append(b); - } - return this; - } - - /** - * Writes a boolean value to this stream followed by a {@linkplain #LINE_SEPARATOR line separator}. - * - * @param b the value to be printed - * @return this {@link LogStream} instance - */ - public LogStream println(boolean b) { - if (ps != null) { - indent(); - lineBuffer.append(b); - return flushLine(true); - } - return this; - } - - /** - * Writes a character value to this stream. - * - * @param c the value to be printed - * @return this {@link LogStream} instance - */ - public LogStream print(char c) { - if (ps != null) { - indent(); - lineBuffer.append(c); - if (c == '\n') { - if (lineBuffer.indexOf(LINE_SEPARATOR, lineBuffer.length() - LINE_SEPARATOR.length()) != -1) { - flushLine(false); - } - } - } - return this; - } - - /** - * Writes a character value to this stream followed by a {@linkplain #LINE_SEPARATOR line separator}. - * - * @param c the value to be printed - * @return this {@link LogStream} instance - */ - public LogStream println(char c) { - if (ps != null) { - indent(); - lineBuffer.append(c); - flushLine(true); - } - return this; - } - - /** - * Prints an int value. - * - * @param i the value to be printed - * @return this {@link LogStream} instance - */ - public LogStream print(int i) { - if (ps != null) { - indent(); - lineBuffer.append(i); - } - return this; - } - - /** - * Writes an int value to this stream followed by a {@linkplain #LINE_SEPARATOR line separator}. - * - * @param i the value to be printed - * @return this {@link LogStream} instance - */ - public LogStream println(int i) { - if (ps != null) { - indent(); - lineBuffer.append(i); - return flushLine(true); - } - return this; - } - - /** - * Writes a float value to this stream. - * - * @param f the value to be printed - * @return this {@link LogStream} instance - */ - public LogStream print(float f) { - if (ps != null) { - indent(); - lineBuffer.append(f); - } - return this; - } - - /** - * Writes a float value to this stream followed by a {@linkplain #LINE_SEPARATOR line separator}. - * - * @param f the value to be printed - * @return this {@link LogStream} instance - */ - public LogStream println(float f) { - if (ps != null) { - indent(); - lineBuffer.append(f); - return flushLine(true); - } - return this; - } - - /** - * Writes a long value to this stream. - * - * @param l the value to be printed - * @return this {@link LogStream} instance - */ - public LogStream print(long l) { - if (ps != null) { - indent(); - lineBuffer.append(l); - } - return this; - } - - /** - * Writes a long value to this stream followed by a {@linkplain #LINE_SEPARATOR line separator}. - * - * @param l the value to be printed - * @return this {@link LogStream} instance - */ - public LogStream println(long l) { - if (ps != null) { - indent(); - lineBuffer.append(l); - return flushLine(true); - } - return this; - } - - /** - * Writes a double value to this stream. - * - * @param d the value to be printed - * @return this {@link LogStream} instance - */ - public LogStream print(double d) { - if (ps != null) { - indent(); - lineBuffer.append(d); - } - return this; - } - - /** - * Writes a double value to this stream followed by a {@linkplain #LINE_SEPARATOR line separator}. - * - * @param d the value to be printed - * @return this {@link LogStream} instance - */ - public LogStream println(double d) { - if (ps != null) { - indent(); - lineBuffer.append(d); - return flushLine(true); - } - return this; - } - - /** - * Writes a {@code String} value to this stream. This method ensures that the {@linkplain #position() position} - * of this stream is updated correctly with respect to any {@linkplain #LINE_SEPARATOR line separators} - * present in {@code s}. - * - * @param s the value to be printed - * @return this {@link LogStream} instance - */ - public LogStream print(String s) { - if (ps != null) { - if (s == null) { - indent(); - lineBuffer.append(s); - return this; - } - - int index = 0; - int next = s.indexOf(LINE_SEPARATOR, index); - while (index < s.length()) { - indent(); - if (next > index) { - lineBuffer.append(s.substring(index, next)); - flushLine(true); - index = next + LINE_SEPARATOR.length(); - next = s.indexOf(LINE_SEPARATOR, index); - } else { - lineBuffer.append(s.substring(index)); - break; - } - } - } - return this; - } - - /** - * Writes a {@code String} value to this stream followed by a {@linkplain #LINE_SEPARATOR line separator}. - * - * @param s the value to be printed - * @return this {@link LogStream} instance - */ - public LogStream println(String s) { - if (ps != null) { - print(s); - flushLine(true); - } - return this; - } - - /** - * Writes a formatted string to this stream. - * - * @param format a format string as described in {@link String#format(String, Object...)} - * @param args the arguments to be formatted - * @return this {@link LogStream} instance - */ - public LogStream printf(String format, Object... args) { - if (ps != null) { - print(String.format(format, args)); - } - return this; - } - - /** - * Writes an instruction formatted as a {@linkplain com.sun.c1x.util.Util#valueString(com.sun.c1x.ir.Value) value} to this stream. - * - * @param value the instruction to print - * @return this {@code LogStream} instance - */ - public LogStream print(Value value) { - if (ps != null) { - indent(); - lineBuffer.append(Util.valueString(value)); - } - return this; - } - - /** - * Writes an instruction formatted as a {@linkplain com.sun.c1x.util.Util#valueString(com.sun.c1x.ir.Value) value} to this stream - * followed by a {@linkplain #LINE_SEPARATOR line separator}. - * - * @param value the instruction to print - * @return this {@code LogStream} instance - */ - public LogStream println(Value value) { - if (ps != null) { - print(value); - flushLine(true); - } - return this; - } - - /** - * Writes a {@linkplain #LINE_SEPARATOR line separator} to this stream. - * - * @return this {@code LogStream} instance - */ - public LogStream println() { - if (ps != null) { - indent(); - flushLine(true); - } - return this; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/debug/TTY.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/debug/TTY.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,239 +0,0 @@ -/* - * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.debug; - -import java.io.*; -import java.util.regex.*; - -import com.sun.c1x.util.*; - - -/** - * A collection of static methods for printing debug and informational output to a global {@link LogStream}. - * The output can be (temporarily) suppressed per thread through use of a {@linkplain Filter filter}. - * - * @author Doug Simon - */ -public class TTY { - - /** - * Support for thread-local suppression of {@link TTY}. - * - * @author Doug Simon - */ - public static class Filter { - private LogStream previous; - private final Thread thread = Thread.currentThread(); - - /** - * Creates an object that will suppress {@link TTY} for the current thread if the given filter does not - * {@linkplain #matches(String, Object) match} the given object. To revert the suppression state to how it was - * before this call, the {@link #remove()} method must be called on the suppression object. - * - * @param filter the pattern for matching. If {@code null}, then the match is successful. If it starts with "~", - * then a regular expression {@linkplain Pattern#matches(String, CharSequence) match} is performed - * where the regular expression is specified by {@code filter} without the "~" prefix. Otherwise, a - * simple {@linkplain String#contains(CharSequence) substring} match is performed where {@code - * filter} is the substring used. - * @param object an object whose {@linkplain Object#toString() string} value is matched against {@code filter} - */ - public Filter(String filter, Object object) { - boolean suppressed = false; - if (filter != null) { - String input = object.toString(); - if (filter.startsWith("~")) { - suppressed = !Pattern.matches(filter.substring(1), input); - } else { - suppressed = !input.contains(filter); - } - if (suppressed) { - previous = out(); - out.set(LogStream.SINK); - } - } - } - - /** - * Reverts the suppression state of {@link TTY} to how it was before this object was constructed. - */ - public void remove() { - assert thread == Thread.currentThread(); - if (previous != null) { - out.set(previous); - } - } - } - - public static final String C1X_TTY_LOG_FILE_PROPERTY = "c1x.tty.file"; - - private static final LogStream log; - static { - PrintStream out = System.out; - String value = System.getProperty(C1X_TTY_LOG_FILE_PROPERTY); - if (value != null) { - try { - out = new PrintStream(new FileOutputStream(value)); - } catch (FileNotFoundException e) { - Util.warning("Could not open log file " + value + ": " + e); - } - } - log = new LogStream(out); - } - - private static final ThreadLocal out = new ThreadLocal() { - @Override - protected LogStream initialValue() { - return log; - }; - }; - - public static boolean isSuppressed() { - return out.get() == LogStream.SINK; - } - - /** - * Gets the thread-local log stream to which the static methods of this class send their output. - * This will either be a global log stream or the global {@linkplain LogStream#SINK sink} depending - * on whether any suppression {@linkplain Filter filters} are in effect for the current thread. - */ - public static LogStream out() { - return out.get(); - } - - /** - * @see LogStream#print(String) - */ - public static void print(String s) { - out().print(s); - } - - /** - * @see LogStream#print(int) - */ - public static void print(int i) { - out().print(i); - } - - /** - * @see LogStream#print(long) - */ - public static void print(long i) { - out().print(i); - } - - /** - * @see LogStream#print(char) - */ - public static void print(char c) { - out().print(c); - } - - /** - * @see LogStream#print(boolean) - */ - public static void print(boolean b) { - out().print(b); - } - - /** - * @see LogStream#print(double) - */ - public static void print(double d) { - out().print(d); - } - - /** - * @see LogStream#print(float) - */ - public static void print(float f) { - out().print(f); - } - - /** - * @see LogStream#println(String) - */ - public static void println(String s) { - out().println(s); - } - - /** - * @see LogStream#println() - */ - public static void println() { - out().println(); - } - - /** - * @see LogStream#println(int) - */ - public static void println(int i) { - out().println(i); - } - - /** - * @see LogStream#println(long) - */ - public static void println(long l) { - out().println(l); - } - - /** - * @see LogStream#println(char) - */ - public static void println(char c) { - out().println(c); - } - - /** - * @see LogStream#println(boolean) - */ - public static void println(boolean b) { - out().println(b); - } - - /** - * @see LogStream#println(double) - */ - public static void println(double d) { - out().println(d); - } - - /** - * @see LogStream#println(float) - */ - public static void println(float f) { - out().println(f); - } - - public static void print(String format, Object... args) { - out().printf(format, args); - } - - public static void println(String format, Object... args) { - out().printf(format + "%n", args); - } - - public static void fillTo(int i) { - out().fillTo(i, ' '); - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/debug/package-info.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/debug/package-info.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2010, 2010, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -/** - * A collection of debugging aids for C1X development. - */ -package com.sun.c1x.debug; diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/gen/LIRGenerator.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/gen/LIRGenerator.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1645 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.gen; - -import static com.sun.cri.bytecode.Bytecodes.*; -import static com.sun.cri.bytecode.Bytecodes.MemoryBarriers.*; -import static com.sun.cri.ci.CiCallingConvention.Type.*; -import static com.sun.cri.ci.CiValue.*; - -import java.lang.reflect.*; -import java.util.*; - -import com.oracle.graal.graph.*; -import com.oracle.max.asm.*; -import com.sun.c1x.*; -import com.sun.c1x.alloc.*; -import com.sun.c1x.alloc.OperandPool.*; -import com.sun.c1x.debug.*; -import com.sun.c1x.globalstub.*; -import com.sun.c1x.graph.*; -import com.sun.c1x.ir.*; -import com.sun.c1x.lir.*; -import com.sun.c1x.util.*; -import com.sun.c1x.value.*; -import com.sun.cri.ci.*; -import com.sun.cri.ri.*; -import com.sun.cri.xir.*; -import com.sun.cri.xir.CiXirAssembler.*; - -/** - * This class traverses the HIR instructions and generates LIR instructions from them. - */ -public abstract class LIRGenerator extends ValueVisitor { - - /** - * Helper class for inserting memory barriers as necessary to implement the Java Memory Model - * with respect to volatile field accesses. - * - * @see MemoryBarriers - */ - class VolatileMemoryAccess { - /** - * Inserts any necessary memory barriers before a volatile write as required by the JMM. - */ - void preVolatileWrite() { - int barriers = compilation.target.arch.requiredBarriers(JMM_PRE_VOLATILE_WRITE); - if (compilation.target.isMP && barriers != 0) { - lir.membar(barriers); - } - } - - /** - * Inserts any necessary memory barriers after a volatile write as required by the JMM. - */ - void postVolatileWrite() { - int barriers = compilation.target.arch.requiredBarriers(JMM_POST_VOLATILE_WRITE); - if (compilation.target.isMP && barriers != 0) { - lir.membar(barriers); - } - } - - /** - * Inserts any necessary memory barriers before a volatile read as required by the JMM. - */ - void preVolatileRead() { - int barriers = compilation.target.arch.requiredBarriers(JMM_PRE_VOLATILE_READ); - if (compilation.target.isMP && barriers != 0) { - lir.membar(barriers); - } - } - - /** - * Inserts any necessary memory barriers after a volatile read as required by the JMM. - */ - void postVolatileRead() { - // Ensure field's data is loaded before any subsequent loads or stores. - int barriers = compilation.target.arch.requiredBarriers(LOAD_LOAD | LOAD_STORE); - if (compilation.target.isMP && barriers != 0) { - lir.membar(barriers); - } - } - } - - /** - * Forces the result of a given instruction to be available in a given register, - * inserting move instructions if necessary. - * - * @param instruction an instruction that produces a {@linkplain Value#operand() result} - * @param register the {@linkplain CiRegister} in which the result of {@code instruction} must be available - * @return {@code register} as an operand - */ - protected CiValue force(Value instruction, CiRegister register) { - return force(instruction, register.asValue(instruction.kind)); - } - - /** - * Forces the result of a given instruction to be available in a given operand, - * inserting move instructions if necessary. - * - * @param instruction an instruction that produces a {@linkplain Value#operand() result} - * @param operand the operand in which the result of {@code instruction} must be available - * @return {@code operand} - */ - protected CiValue force(Value instruction, CiValue operand) { - CiValue result = makeOperand(instruction); - if (result != operand) { - assert result.kind != CiKind.Illegal; - if (!compilation.archKindsEqual(result.kind, operand.kind)) { - // moves between different types need an intervening spill slot - CiValue tmp = forceToSpill(result, operand.kind, false); - lir.move(tmp, operand); - } else { - lir.move(result, operand); - } - } - return operand; - } - - protected CiValue load(Value val) { - CiValue result = makeOperand(val); - if (!result.isVariableOrRegister()) { - CiVariable operand = newVariable(val.kind); - lir.move(result, operand); - return operand; - } - return result; - } - - // the range of values in a lookupswitch or tableswitch statement - private static final class SwitchRange { - final int lowKey; - int highKey; - final LIRBlock sux; - - SwitchRange(int lowKey, LIRBlock sux) { - this.lowKey = lowKey; - this.highKey = lowKey; - this.sux = sux; - } - } - - protected final C1XCompilation compilation; - protected final IR ir; - protected final XirSupport xirSupport; - protected final RiXirGenerator xir; - protected final boolean isTwoOperand; - - private LIRBlock currentBlock; - - public final OperandPool operands; - - private Value currentInstruction; - private Value lastInstructionPrinted; // Debugging only - - private List constants; - private List variablesForConstants; - protected LIRList lir; - final VolatileMemoryAccess vma; - private ArrayList deoptimizationStubs; - private FrameState lastState; - - public LIRGenerator(C1XCompilation compilation) { - this.compilation = compilation; - this.ir = compilation.hir(); - this.xir = compilation.compiler.xir; - this.xirSupport = new XirSupport(); - this.isTwoOperand = compilation.target.arch.twoOperandMode(); - this.vma = new VolatileMemoryAccess(); - - constants = new ArrayList(); - variablesForConstants = new ArrayList(); - - this.operands = new OperandPool(compilation.target); - } - - public ArrayList deoptimizationStubs() { - return deoptimizationStubs; - } - - private void addDeoptimizationStub(DeoptimizationStub stub) { - if (deoptimizationStubs == null) { - deoptimizationStubs = new ArrayList(); - } - deoptimizationStubs.add(stub); - } - - public static class DeoptimizationStub { - public final Label label = new Label(); - public final LIRDebugInfo info; - - public DeoptimizationStub(FrameState state) { - info = new LIRDebugInfo(state); - } - } - - public void doBlock(LIRBlock block) { - blockDoProlog(block); - this.currentBlock = block; - - if (C1XOptions.TraceLIRGeneratorLevel >= 1) { - TTY.println("BEGIN Generating LIR for block B" + block.blockID()); - } - - if (block.blockPredecessors().size() > 1) { - lastState = null; - } - - for (Node instr : block.getInstructions()) { - FrameState stateAfter = null; - if (instr instanceof Instruction) { - stateAfter = ((Instruction) instr).stateAfter(); - } - FrameState stateBefore = null; - if (instr instanceof StateSplit && ((StateSplit) instr).stateBefore() != null) { - stateBefore = ((StateSplit) instr).stateBefore(); - } - if (stateBefore != null) { - lastState = stateBefore; - if (C1XOptions.TraceLIRGeneratorLevel >= 2) { - TTY.println("STATE CHANGE (stateBefore)"); - if (C1XOptions.TraceLIRGeneratorLevel >= 3) { - TTY.println(stateBefore.toString()); - } - } - } - if (!(instr instanceof Merge) && instr != instr.graph().start()) { - walkState(instr, stateAfter); - doRoot((Value) instr); - } - if (stateAfter != null) { - lastState = stateAfter; - if (C1XOptions.TraceLIRGeneratorLevel >= 2) { - TTY.println("STATE CHANGE"); - if (C1XOptions.TraceLIRGeneratorLevel >= 3) { - TTY.println(stateAfter.toString()); - } - } - } - } - if (block.blockSuccessors().size() >= 1 && (block.getInstructions().size() == 0 || !jumpsToNextBlock(block.getInstructions().get(block.getInstructions().size() - 1)))) { - moveToPhi(); - block.lir().jump(block.blockSuccessors().get(0)); - } - - if (C1XOptions.TraceLIRGeneratorLevel >= 1) { - TTY.println("END Generating LIR for block B" + block.blockID()); - } - - block.setLastState(lastState); - this.currentBlock = null; - blockDoEpilog(); - } - - private static boolean jumpsToNextBlock(Node node) { - return node instanceof BlockEnd; - } - - @Override - public void visitArrayLength(ArrayLength x) { - emitArrayLength(x); - } - - public CiValue emitArrayLength(ArrayLength x) { - XirArgument array = toXirArgument(x.array()); - XirSnippet snippet = xir.genArrayLength(site(x), array); - emitXir(snippet, x, stateFor(x), null, true); - return x.operand(); - } - - private FrameState setOperandsForLocals() { - CiCallingConvention args = compilation.frameMap().incomingArguments(); - int bci = 0; - if (Modifier.isSynchronized(compilation.method.accessFlags())) { - bci = Instruction.SYNCHRONIZATION_ENTRY_BCI; - } - FrameState fs = new FrameState(compilation.method, bci, compilation.method.maxLocals(), 0, 0, compilation.graph); - for (Node node : compilation.graph.start().usages()) { - if (node instanceof Local) { - Local local = (Local) node; - int i = local.index(); - fs.storeLocal(i, local); - - CiValue src = args.locations[i]; - assert src.isLegal() : "check"; - - CiVariable dest = newVariable(src.kind.stackKind()); - lir.move(src, dest, src.kind); - - assert src.kind.stackKind() == local.kind.stackKind() : "local type check failed"; - setResult(local, dest); - } - } - return fs; - } - - @Override - public void visitCheckCast(CheckCast x) { - XirArgument obj = toXirArgument(x.object()); - XirSnippet snippet = xir.genCheckCast(site(x), obj, toXirArgument(x.targetClassInstruction()), x.targetClass()); - emitXir(snippet, x, stateFor(x), null, true); - } - - @Override - public void visitInstanceOf(InstanceOf x) { - XirArgument obj = toXirArgument(x.object()); - XirSnippet snippet = xir.genInstanceOf(site(x), obj, toXirArgument(x.targetClassInstruction()), x.targetClass()); - emitXir(snippet, x, stateFor(x), null, true); - } - - @Override - public void visitMonitorEnter(MonitorEnter x) { - XirArgument obj = toXirArgument(x.object()); - XirArgument lockAddress = toXirArgument(x.lockAddress()); - XirSnippet snippet = xir.genMonitorEnter(site(x), obj, lockAddress); - emitXir(snippet, x, stateFor(x), stateFor(x, x.stateAfter()), null, true, null); - } - - @Override - public void visitMonitorExit(MonitorExit x) { - XirArgument obj = toXirArgument(x.object()); - XirArgument lockAddress = toXirArgument(x.lockAddress()); - XirSnippet snippet = xir.genMonitorExit(site(x), obj, lockAddress); - emitXir(snippet, x, stateFor(x), null, true); - } - - @Override - public void visitStoreIndexed(StoreIndexed x) { - XirArgument array = toXirArgument(x.array()); - XirArgument length = x.length() == null ? null : toXirArgument(x.length()); - XirArgument index = toXirArgument(x.index()); - XirArgument value = toXirArgument(x.value()); - XirSnippet snippet = xir.genArrayStore(site(x), array, index, length, value, x.elementKind(), null); - emitXir(snippet, x, stateFor(x), null, true); - } - - @Override - public void visitNewInstance(NewInstance x) { - XirSnippet snippet = xir.genNewInstance(site(x), x.instanceClass()); - emitXir(snippet, x, stateFor(x), null, true); - } - - @Override - public void visitNewTypeArray(NewTypeArray x) { - XirArgument length = toXirArgument(x.length()); - XirSnippet snippet = xir.genNewArray(site(x), length, x.elementKind(), null, null); - emitXir(snippet, x, stateFor(x), null, true); - } - - @Override - public void visitNewObjectArray(NewObjectArray x) { - XirArgument length = toXirArgument(x.length()); - XirSnippet snippet = xir.genNewArray(site(x), length, CiKind.Object, x.elementClass(), x.exactType()); - emitXir(snippet, x, stateFor(x), null, true); - } - - @Override - public void visitNewMultiArray(NewMultiArray x) { - XirArgument[] dims = new XirArgument[x.dimensionCount()]; - - for (int i = 0; i < dims.length; i++) { - dims[i] = toXirArgument(x.dimension(i)); - } - - XirSnippet snippet = xir.genNewMultiArray(site(x), dims, x.elementType); - emitXir(snippet, x, stateFor(x), null, true); - } - - @Override - public void visitConstant(Constant x) { - if (!canInlineAsConstant(x)) { - CiValue res = x.operand(); - if (!(res.isLegal())) { - res = x.asConstant(); - } - if (res.isConstant()) { - CiVariable reg = createResultVariable(x); - lir.move(res, reg); - } else { - setResult(x, (CiVariable) res); - } - } - } - - @Override - public void visitExceptionObject(ExceptionObject x) { - XirSnippet snippet = xir.genExceptionObject(site(x)); - emitXir(snippet, x, stateFor(x), null, true); - } - - @Override - public void visitAnchor(Anchor x) { - setNoResult(x); - - // emit phi-instruction moves after safepoint since this simplifies - // describing the state at the safepoint. - - moveToPhi(); - lir.jump(getLIRBlock(x.defaultSuccessor())); - } - - @Override - public void visitIfOp(Conditional i) { - Value x = i.x(); - Value y = i.y(); - CiKind xtype = x.kind; - CiKind ttype = i.trueValue().kind; - assert xtype.isInt() || xtype.isObject() : "cannot handle others"; - assert ttype.isInt() || ttype.isObject() || ttype.isLong() || ttype.isWord() : "cannot handle others"; - assert ttype.equals(i.falseValue().kind) : "cannot handle others"; - - CiValue left = load(x); - CiValue right = null; - if (!canInlineAsConstant(y)) { - right = load(y); - } else { - right = makeOperand(y); - } - - CiValue tVal = makeOperand(i.trueValue()); - CiValue fVal = makeOperand(i.falseValue()); - CiValue reg = createResultVariable(i); - - lir.cmp(i.condition(), left, right); - lir.cmove(i.condition(), tVal, fVal, reg); - } - - protected FrameState stateBeforeInvokeReturn(Invoke invoke) { - return invoke.stateAfter().duplicateModified(getBeforeInvokeBci(invoke), invoke.kind); - } - - protected FrameState stateBeforeInvokeWithArguments(Invoke invoke) { - Value[] args = new Value[invoke.argumentCount()]; - for (int i = 0; i < invoke.argumentCount(); i++) { - args[i] = invoke.argument(i); - } - return invoke.stateAfter().duplicateModified(getBeforeInvokeBci(invoke), invoke.kind, args); - } - - private int getBeforeInvokeBci(Invoke invoke) { - /*int length = 3; - if (invoke.opcode() == Bytecodes.INVOKEINTERFACE) { - length += 2; - } - return invoke.stateAfter().bci - length;*/ - return invoke.bci; - } - - @Override - public void visitInvoke(Invoke x) { - RiMethod target = x.target(); - LIRDebugInfo info = stateFor(x, stateBeforeInvokeWithArguments(x)); - LIRDebugInfo info2 = stateFor(x, stateBeforeInvokeReturn(x)); - if (x.exceptionEdge() != null) { - info2.setExceptionEdge(getLIRBlock(x.exceptionEdge())); - } - - XirSnippet snippet = null; - - int opcode = x.opcode(); - XirArgument receiver; - switch (opcode) { - case INVOKESTATIC: - snippet = xir.genInvokeStatic(site(x), target); - break; - case INVOKESPECIAL: - receiver = toXirArgument(x.receiver()); - snippet = xir.genInvokeSpecial(site(x), receiver, target); - break; - case INVOKEVIRTUAL: - receiver = toXirArgument(x.receiver()); - snippet = xir.genInvokeVirtual(site(x), receiver, target); - break; - case INVOKEINTERFACE: - receiver = toXirArgument(x.receiver()); - snippet = xir.genInvokeInterface(site(x), receiver, target); - break; - } - - CiValue destinationAddress = null; - // emitting the template earlier can ease pressure on register allocation, but the argument loading can destroy an - // implicit calling convention between the XirSnippet and the call. - if (!C1XOptions.InvokeSnippetAfterArguments) { - destinationAddress = emitXir(snippet, x, info.copy(), x.target(), false); - } - - CiValue resultOperand = resultOperandFor(x.kind); - CiCallingConvention cc = compilation.frameMap().getCallingConvention(x.signature(), JavaCall); - List pointerSlots = new ArrayList(2); - List argList = visitInvokeArguments(cc, x, pointerSlots); - - if (C1XOptions.InvokeSnippetAfterArguments) { - destinationAddress = emitXir(snippet, x, info.copy(), null, x.target(), false, pointerSlots); - } - - // emit direct or indirect call to the destination address - if (destinationAddress instanceof CiConstant) { - // Direct call - assert ((CiConstant) destinationAddress).isDefaultValue() : "destination address should be zero"; - lir.callDirect(target, resultOperand, argList, info2, snippet.marks, pointerSlots); - } else { - // Indirect call - argList.add(destinationAddress); - lir.callIndirect(target, resultOperand, argList, info2, snippet.marks, pointerSlots); - } - - if (resultOperand.isLegal()) { - CiValue result = createResultVariable(x); - lir.move(resultOperand, result); - } - } - - @Override - public void visitMonitorAddress(MonitorAddress x) { - CiValue result = createResultVariable(x); - lir.monitorAddress(x.monitor(), result); - } - - /** - * For note on volatile fields, see {@link #visitStoreField(StoreField)}. - */ - @Override - public void visitLoadField(LoadField x) { - RiField field = x.field(); - LIRDebugInfo info = stateFor(x); - XirArgument receiver = toXirArgument(x.object()); - XirSnippet snippet = x.isStatic() ? xir.genGetStatic(site(x), receiver, field) : xir.genGetField(site(x), receiver, field); - emitXir(snippet, x, info, null, true); - - if (x.isVolatile()) { - vma.postVolatileRead(); - } - } - - @Override - public void visitLoadIndexed(LoadIndexed x) { - XirArgument array = toXirArgument(x.array()); - XirArgument index = toXirArgument(x.index()); - XirArgument length = toXirArgument(x.length()); - XirSnippet snippet = xir.genArrayLoad(site(x), array, index, length, x.elementKind(), null); - emitXir(snippet, x, stateFor(x), null, true); - } - - protected GlobalStub stubFor(CiRuntimeCall runtimeCall) { - GlobalStub stub = compilation.compiler.lookupGlobalStub(runtimeCall); - compilation.frameMap().usesGlobalStub(stub); - return stub; - } - - protected GlobalStub stubFor(GlobalStub.Id globalStub) { - GlobalStub stub = compilation.compiler.lookupGlobalStub(globalStub); - compilation.frameMap().usesGlobalStub(stub); - return stub; - } - - protected GlobalStub stubFor(XirTemplate template) { - GlobalStub stub = compilation.compiler.lookupGlobalStub(template); - compilation.frameMap().usesGlobalStub(stub); - return stub; - } - - @Override - public void visitLocal(Local x) { - if (x.operand().isIllegal()) { - createResultVariable(x); - } - } - - @Override - public void visitLookupSwitch(LookupSwitch x) { - CiValue tag = load(x.value()); - setNoResult(x); - - if (x.numberOfCases() == 0 || x.numberOfCases() < C1XOptions.SequentialSwitchLimit) { - int len = x.numberOfCases(); - for (int i = 0; i < len; i++) { - lir.cmp(Condition.EQ, tag, x.keyAt(i)); - lir.branch(Condition.EQ, CiKind.Int, getLIRBlock(x.blockSuccessor(i))); - } - lir.jump(getLIRBlock(x.defaultSuccessor())); - } else { - visitSwitchRanges(createLookupRanges(x), tag, getLIRBlock(x.defaultSuccessor())); - } - } - - protected LIRBlock getLIRBlock(Instruction b) { - LIRBlock result = ir.valueToBlock.get(b); - if (result == null) { - TTY.println("instruction without lir block: " + b); - } - return result; - } - - @Override - public void visitNullCheck(NullCheck x) { - CiValue value = load(x.object()); - LIRDebugInfo info = stateFor(x); - lir.nullCheck(value, info); - } - - @Override - public void visitPhi(Phi i) { - Util.shouldNotReachHere(); - } - - @Override - public void visitReturn(Return x) { - if (x.kind.isVoid()) { - XirSnippet epilogue = xir.genEpilogue(site(x), compilation.method); - if (epilogue != null) { - emitXir(epilogue, x, null, compilation.method, false); - lir.returnOp(IllegalValue); - } - } else { - CiValue operand = resultOperandFor(x.kind); - CiValue result = force(x.result(), operand); - XirSnippet epilogue = xir.genEpilogue(site(x), compilation.method); - if (epilogue != null) { - emitXir(epilogue, x, null, compilation.method, false); - lir.returnOp(result); - } - } - setNoResult(x); - } - - protected XirArgument toXirArgument(CiValue v) { - if (v == null) { - return null; - } - - return XirArgument.forInternalObject(v); - } - - protected XirArgument toXirArgument(Value i) { - if (i == null) { - return null; - } - - return XirArgument.forInternalObject(new LIRItem(i, this)); - } - - private CiValue allocateOperand(XirSnippet snippet, XirOperand op) { - if (op instanceof XirParameter) { - XirParameter param = (XirParameter) op; - return allocateOperand(snippet.arguments[param.parameterIndex], op, param.canBeConstant); - } else if (op instanceof XirRegister) { - XirRegister reg = (XirRegister) op; - return reg.register; - } else if (op instanceof XirTemp) { - return newVariable(op.kind); - } else { - Util.shouldNotReachHere(); - return null; - } - } - - private CiValue allocateOperand(XirArgument arg, XirOperand var, boolean canBeConstant) { - if (arg.constant != null) { - return arg.constant; - } else { - assert arg.object != null; - if (arg.object instanceof CiValue) { - return (CiValue) arg.object; - } - assert arg.object instanceof LIRItem; - LIRItem item = (LIRItem) arg.object; - if (canBeConstant) { - return item.instruction.operand(); - } else { - CiKind kind = var.kind; - if (kind == CiKind.Byte || kind == CiKind.Boolean) { - item.loadByteItem(); - } else { - item.loadItem(); - } - return item.result(); - } - } - } - - protected CiValue emitXir(XirSnippet snippet, Value x, LIRDebugInfo info, RiMethod method, boolean setInstructionResult) { - return emitXir(snippet, x, info, null, method, setInstructionResult, null); - } - - protected CiValue emitXir(XirSnippet snippet, Value instruction, LIRDebugInfo info, LIRDebugInfo infoAfter, RiMethod method, boolean setInstructionResult, List pointerSlots) { - if (C1XOptions.PrintXirTemplates) { - TTY.println("Emit XIR template " + snippet.template.name); - } - - final CiValue[] operands = new CiValue[snippet.template.variableCount]; - - compilation.frameMap().reserveOutgoing(snippet.template.outgoingStackSize); - - XirOperand resultOperand = snippet.template.resultOperand; - - if (snippet.template.allocateResultOperand) { - CiValue outputOperand = IllegalValue; - // This snippet has a result that must be separately allocated - // Otherwise it is assumed that the result is part of the inputs - if (resultOperand.kind != CiKind.Void && resultOperand.kind != CiKind.Illegal) { - if (setInstructionResult) { - outputOperand = newVariable(instruction.kind); - } else { - outputOperand = newVariable(resultOperand.kind); - } - assert operands[resultOperand.index] == null; - } - operands[resultOperand.index] = outputOperand; - if (C1XOptions.PrintXirTemplates) { - TTY.println("Output operand: " + outputOperand); - } - } - - for (XirTemp t : snippet.template.temps) { - if (t instanceof XirRegister) { - XirRegister reg = (XirRegister) t; - if (!t.reserve) { - operands[t.index] = reg.register; - } - } - } - - for (XirTemplate calleeTemplate : snippet.template.calleeTemplates) { - // TODO Save these for use in X86LIRAssembler - stubFor(calleeTemplate); - } - - for (XirConstant c : snippet.template.constants) { - assert operands[c.index] == null; - operands[c.index] = c.value; - } - - XirOperand[] inputOperands = snippet.template.inputOperands; - XirOperand[] inputTempOperands = snippet.template.inputTempOperands; - XirOperand[] tempOperands = snippet.template.tempOperands; - - CiValue[] operandArray = new CiValue[inputOperands.length + inputTempOperands.length + tempOperands.length]; - int[] operandIndicesArray = new int[inputOperands.length + inputTempOperands.length + tempOperands.length]; - for (int i = 0; i < inputOperands.length; i++) { - XirOperand x = inputOperands[i]; - CiValue op = allocateOperand(snippet, x); - operands[x.index] = op; - operandArray[i] = op; - operandIndicesArray[i] = x.index; - if (C1XOptions.PrintXirTemplates) { - TTY.println("Input operand: " + x); - } - } - - for (int i = 0; i < inputTempOperands.length; i++) { - XirOperand x = inputTempOperands[i]; - CiValue op = allocateOperand(snippet, x); - CiValue newOp = newVariable(op.kind); - lir.move(op, newOp); - operands[x.index] = newOp; - operandArray[i + inputOperands.length] = newOp; - operandIndicesArray[i + inputOperands.length] = x.index; - if (C1XOptions.PrintXirTemplates) { - TTY.println("InputTemp operand: " + x); - } - } - - for (int i = 0; i < tempOperands.length; i++) { - XirOperand x = tempOperands[i]; - CiValue op = allocateOperand(snippet, x); - operands[x.index] = op; - operandArray[i + inputOperands.length + inputTempOperands.length] = op; - operandIndicesArray[i + inputOperands.length + inputTempOperands.length] = x.index; - if (C1XOptions.PrintXirTemplates) { - TTY.println("Temp operand: " + x); - } - } - - for (CiValue operand : operands) { - assert operand != null; - } - - CiValue allocatedResultOperand = operands[resultOperand.index]; - if (!allocatedResultOperand.isVariableOrRegister()) { - allocatedResultOperand = IllegalValue; - } - - if (setInstructionResult && allocatedResultOperand.isLegal()) { - if (instruction.operand().isIllegal()) { - setResult(instruction, (CiVariable) allocatedResultOperand); - } else { - assert instruction.operand() == allocatedResultOperand; - } - } - - - XirInstruction[] slowPath = snippet.template.slowPath; - if (!operands[resultOperand.index].isConstant() || snippet.template.fastPath.length != 0 || (slowPath != null && slowPath.length > 0)) { - // XIR instruction is only needed when the operand is not a constant! - lir.xir(snippet, operands, allocatedResultOperand, inputTempOperands.length, tempOperands.length, - operandArray, operandIndicesArray, - (operands[resultOperand.index] == IllegalValue) ? -1 : resultOperand.index, - info, infoAfter, method, pointerSlots); - } - - return operands[resultOperand.index]; - } - - @Override - public void visitStoreField(StoreField x) { - RiField field = x.field(); - LIRDebugInfo info = stateFor(x); - - if (x.isVolatile()) { - vma.preVolatileWrite(); - } - - XirArgument receiver = toXirArgument(x.object()); - XirArgument value = toXirArgument(x.value()); - XirSnippet snippet = x.isStatic() ? xir.genPutStatic(site(x), receiver, field, value) : xir.genPutField(site(x), receiver, field, value); - emitXir(snippet, x, info, null, true); - - if (x.isVolatile()) { - vma.postVolatileWrite(); - } - } - - @Override - public void visitTableSwitch(TableSwitch x) { - - LIRItem value = new LIRItem(x.value(), this); - // Making a copy of the switch value is necessary when generating a jump table - value.setDestroysRegister(); - value.loadItem(); - - CiValue tag = value.result(); - setNoResult(x); - - // TODO: tune the defaults for the controls used to determine what kind of translation to use - if (x.numberOfCases() == 0 || x.numberOfCases() <= C1XOptions.SequentialSwitchLimit) { - int loKey = x.lowKey(); - int len = x.numberOfCases(); - for (int i = 0; i < len; i++) { - lir.cmp(Condition.EQ, tag, i + loKey); - lir.branch(Condition.EQ, CiKind.Int, getLIRBlock(x.blockSuccessor(i))); - } - lir.jump(getLIRBlock(x.defaultSuccessor())); - } else { - SwitchRange[] switchRanges = createLookupRanges(x); - int rangeDensity = x.numberOfCases() / switchRanges.length; - if (rangeDensity >= C1XOptions.RangeTestsSwitchDensity) { - visitSwitchRanges(switchRanges, tag, getLIRBlock(x.defaultSuccessor())); - } else { - List nonDefaultSuccessors = x.blockSuccessors().subList(0, x.numberOfCases()); - LIRBlock[] targets = new LIRBlock[nonDefaultSuccessors.size()]; - for (int i = 0; i < nonDefaultSuccessors.size(); ++i) { - targets[i] = getLIRBlock(nonDefaultSuccessors.get(i)); - } - lir.tableswitch(tag, x.lowKey(), getLIRBlock(x.defaultSuccessor()), targets); - } - } - } - - @Override - public void visitDeoptimize(Deoptimize deoptimize) { - DeoptimizationStub stub = new DeoptimizationStub(lastState); - addDeoptimizationStub(stub); - lir.branch(Condition.TRUE, stub.label, stub.info); - } - - private void blockDoEpilog() { - if (C1XOptions.PrintIRWithLIR) { - TTY.println(); - } - - // clear out variables for local constants - constants.clear(); - variablesForConstants.clear(); - } - - private void blockDoProlog(LIRBlock block) { - if (C1XOptions.PrintIRWithLIR) { - TTY.print(block.toString()); - } - // set up the list of LIR instructions - assert block.lir() == null : "LIR list already computed for this block"; - lir = new LIRList(this); - block.setLir(lir); - - lir.branchDestination(block.label()); - if (block == ir.startBlock) { - XirSnippet prologue = xir.genPrologue(null, compilation.method); - if (prologue != null) { - emitXir(prologue, null, null, null, false); - } - FrameState fs = setOperandsForLocals(); - lastState = fs; - } else if (block.blockPredecessors().size() == 1) { - FrameState fs = block.blockPredecessors().get(0).lastState(); - assert fs != null; - lastState = fs; - } - } - - /** - * Copies a given value into an operand that is forced to be a stack location. - * - * @param value a value to be forced onto the stack - * @param kind the kind of new operand - * @param mustStayOnStack specifies if the new operand must never be allocated to a register - * @return the operand that is guaranteed to be a stack location when it is - * initially defined a by move from {@code value} - */ - CiValue forceToSpill(CiValue value, CiKind kind, boolean mustStayOnStack) { - assert value.isLegal() : "value should not be illegal"; - assert kind.jvmSlots == value.kind.jvmSlots : "size mismatch"; - if (!value.isVariableOrRegister()) { - // force into a variable that must start in memory - CiValue operand = operands.newVariable(value.kind, mustStayOnStack ? VariableFlag.MustStayInMemory : VariableFlag.MustStartInMemory); - lir.move(value, operand); - return operand; - } - - // create a spill location - CiValue operand = operands.newVariable(kind, mustStayOnStack ? VariableFlag.MustStayInMemory : VariableFlag.MustStartInMemory); - // move from register to spill - lir.move(value, operand); - return operand; - } - - private CiVariable loadConstant(Constant x) { - return loadConstant(x.asConstant(), x.kind); - } - - protected CiVariable loadConstant(CiConstant c, CiKind kind) { - // XXX: linear search might be kind of slow for big basic blocks - int index = constants.indexOf(c); - if (index != -1) { - C1XMetrics.LoadConstantIterations += index; - return variablesForConstants.get(index); - } - C1XMetrics.LoadConstantIterations += constants.size(); - - CiVariable result = newVariable(kind); - lir.move(c, result); - constants.add(c); - variablesForConstants.add(result); - return result; - } - - /** - * Allocates a variable operand to hold the result of a given instruction. - * This can only be performed once for any given instruction. - * - * @param x an instruction that produces a result - * @return the variable assigned to hold the result produced by {@code x} - */ - protected CiVariable createResultVariable(Value x) { - CiVariable operand = newVariable(x.kind); - setResult(x, operand); - return operand; - } - - @Override - public void visitRegisterFinalizer(RegisterFinalizer x) { - CiValue receiver = load(x.object()); - LIRDebugInfo info = stateFor(x, x.stateBefore()); - callRuntime(CiRuntimeCall.RegisterFinalizer, info, receiver); - setNoResult(x); - } - - private void visitSwitchRanges(SwitchRange[] x, CiValue value, LIRBlock defaultSux) { - for (int i = 0; i < x.length; i++) { - SwitchRange oneRange = x[i]; - int lowKey = oneRange.lowKey; - int highKey = oneRange.highKey; - LIRBlock dest = oneRange.sux; - if (lowKey == highKey) { - lir.cmp(Condition.EQ, value, lowKey); - lir.branch(Condition.EQ, CiKind.Int, dest); - } else if (highKey - lowKey == 1) { - lir.cmp(Condition.EQ, value, lowKey); - lir.branch(Condition.EQ, CiKind.Int, dest); - lir.cmp(Condition.EQ, value, highKey); - lir.branch(Condition.EQ, CiKind.Int, dest); - } else { - Label l = new Label(); - lir.cmp(Condition.LT, value, lowKey); - lir.branch(Condition.LT, l); - lir.cmp(Condition.LE, value, highKey); - lir.branch(Condition.LE, CiKind.Int, dest); - lir.branchDestination(l); - } - } - lir.jump(defaultSux); - } - - protected void arithmeticOpFpu(int code, CiValue result, CiValue left, CiValue right, CiValue tmp) { - CiValue leftOp = left; - - if (isTwoOperand && leftOp != result) { - assert right != result : "malformed"; - lir.move(leftOp, result); - leftOp = result; - } - - switch (code) { - case DADD: - case FADD: - lir.add(leftOp, right, result); - break; - case FMUL: - case DMUL: - lir.mul(leftOp, right, result); - break; - case DSUB: - case FSUB: - lir.sub(leftOp, right, result); - break; - case FDIV: - case DDIV: - lir.div(leftOp, right, result, null); - break; - default: - Util.shouldNotReachHere(); - } - } - - protected void arithmeticOpInt(int code, CiValue result, CiValue left, CiValue right, CiValue tmp) { - CiValue leftOp = left; - - if (isTwoOperand && leftOp != result) { - assert right != result : "malformed"; - lir.move(leftOp, result); - leftOp = result; - } - - switch (code) { - case IADD: - lir.add(leftOp, right, result); - break; - case IMUL: - boolean didStrengthReduce = false; - if (right.isConstant()) { - CiConstant rightConstant = (CiConstant) right; - int c = rightConstant.asInt(); - if (CiUtil.isPowerOf2(c)) { - // do not need tmp here - lir.shiftLeft(leftOp, CiUtil.log2(c), result); - didStrengthReduce = true; - } else { - didStrengthReduce = strengthReduceMultiply(leftOp, c, result, tmp); - } - } - // we couldn't strength reduce so just emit the multiply - if (!didStrengthReduce) { - lir.mul(leftOp, right, result); - } - break; - case ISUB: - lir.sub(leftOp, right, result); - break; - default: - // idiv and irem are handled elsewhere - Util.shouldNotReachHere(); - } - } - - protected void arithmeticOpLong(int code, CiValue result, CiValue left, CiValue right, LIRDebugInfo info) { - CiValue leftOp = left; - - if (isTwoOperand && leftOp != result) { - assert right != result : "malformed"; - lir.move(leftOp, result); - leftOp = result; - } - - switch (code) { - case LADD: - lir.add(leftOp, right, result); - break; - case LMUL: - lir.mul(leftOp, right, result); - break; - case LSUB: - lir.sub(leftOp, right, result); - break; - default: - // ldiv and lrem are handled elsewhere - Util.shouldNotReachHere(); - } - } - - protected final CiValue callRuntime(CiRuntimeCall runtimeCall, LIRDebugInfo info, CiValue... args) { - // get a result register - CiKind result = runtimeCall.resultKind; - CiKind[] arguments = runtimeCall.arguments; - - CiValue physReg = result.isVoid() ? IllegalValue : resultOperandFor(result); - - List argumentList; - if (arguments.length > 0) { - // move the arguments into the correct location - CiCallingConvention cc = compilation.frameMap().getCallingConvention(arguments, RuntimeCall); - assert cc.locations.length == args.length : "argument count mismatch"; - for (int i = 0; i < args.length; i++) { - CiValue arg = args[i]; - CiValue loc = cc.locations[i]; - if (loc.isRegister()) { - lir.move(arg, loc); - } else { - assert loc.isStackSlot(); - CiStackSlot slot = (CiStackSlot) loc; - if (slot.kind == CiKind.Long || slot.kind == CiKind.Double) { - lir.unalignedMove(arg, slot); - } else { - lir.move(arg, slot); - } - } - } - argumentList = Arrays.asList(cc.locations); - } else { - // no arguments - assert args == null || args.length == 0; - argumentList = Util.uncheckedCast(Collections.emptyList()); - } - - lir.callRuntime(runtimeCall, physReg, argumentList, info); - - return physReg; - } - - protected final CiVariable callRuntimeWithResult(CiRuntimeCall runtimeCall, LIRDebugInfo info, CiValue... args) { - CiVariable result = newVariable(runtimeCall.resultKind); - CiValue location = callRuntime(runtimeCall, info, args); - lir.move(location, result); - return result; - } - - SwitchRange[] createLookupRanges(LookupSwitch x) { - // we expect the keys to be sorted by increasing value - List res = new ArrayList(x.numberOfCases()); - int len = x.numberOfCases(); - if (len > 0) { - LIRBlock defaultSux = getLIRBlock(x.defaultSuccessor()); - int key = x.keyAt(0); - LIRBlock sux = getLIRBlock(x.blockSuccessor(0)); - SwitchRange range = new SwitchRange(key, sux); - for (int i = 1; i < len; i++) { - int newKey = x.keyAt(i); - LIRBlock newSux = getLIRBlock(x.blockSuccessor(i)); - if (key + 1 == newKey && sux == newSux) { - // still in same range - range.highKey = newKey; - } else { - // skip tests which explicitly dispatch to the default - if (range.sux != defaultSux) { - res.add(range); - } - range = new SwitchRange(newKey, newSux); - } - key = newKey; - sux = newSux; - } - if (res.size() == 0 || res.get(res.size() - 1) != range) { - res.add(range); - } - } - return res.toArray(new SwitchRange[res.size()]); - } - - SwitchRange[] createLookupRanges(TableSwitch x) { - // XXX: try to merge this with the code for LookupSwitch - List res = new ArrayList(x.numberOfCases()); - int len = x.numberOfCases(); - if (len > 0) { - LIRBlock sux = getLIRBlock(x.blockSuccessor(0)); - int key = x.lowKey(); - LIRBlock defaultSux = getLIRBlock(x.defaultSuccessor()); - SwitchRange range = new SwitchRange(key, sux); - for (int i = 0; i < len; i++, key++) { - LIRBlock newSux = getLIRBlock(x.blockSuccessor(i)); - if (sux == newSux) { - // still in same range - range.highKey = key; - } else { - // skip tests which explicitly dispatch to the default - if (sux != defaultSux) { - res.add(range); - } - range = new SwitchRange(key, newSux); - } - sux = newSux; - } - if (res.size() == 0 || res.get(res.size() - 1) != range) { - res.add(range); - } - } - return res.toArray(new SwitchRange[res.size()]); - } - - void doRoot(Value instr) { - if (C1XOptions.TraceLIRGeneratorLevel >= 2) { - TTY.println("Emitting LIR for instruction " + instr); - } - currentInstruction = instr; - - if (C1XOptions.TraceLIRVisit) { - TTY.println("Visiting " + instr); - } - instr.accept(this); - if (C1XOptions.TraceLIRVisit) { - TTY.println("Operand for " + instr + " = " + instr.operand()); - } - } - - protected void logicOp(int code, CiValue resultOp, CiValue leftOp, CiValue rightOp) { - if (isTwoOperand && leftOp != resultOp) { - assert rightOp != resultOp : "malformed"; - lir.move(leftOp, resultOp); - leftOp = resultOp; - } - - switch (code) { - case IAND: - case LAND: - lir.logicalAnd(leftOp, rightOp, resultOp); - break; - - case IOR: - case LOR: - lir.logicalOr(leftOp, rightOp, resultOp); - break; - - case IXOR: - case LXOR: - lir.logicalXor(leftOp, rightOp, resultOp); - break; - - default: - Util.shouldNotReachHere(); - } - } - - void moveToPhi(PhiResolver resolver, Value curVal, Value suxVal, List phis, int predIndex) { - // move current value to referenced phi function - if (suxVal instanceof Phi) { - Phi phi = (Phi) suxVal; - - // curVal can be null without phi being null in conjunction with inlining - if (!phi.isDead() && curVal != null && curVal != phi) { - - assert phis.contains(phi); - if (phi.valueAt(predIndex) != curVal) { - phi.print(TTY.out()); - } - assert phi.valueAt(predIndex) == curVal : "curVal=" + curVal + "valueAt(" + predIndex + ")=" + phi.valueAt(predIndex); - - assert !phi.isDead() : "illegal phi cannot be marked as live"; - if (curVal instanceof Phi) { - operandForPhi((Phi) curVal); - } - CiValue operand = curVal.operand(); - if (operand.isIllegal()) { - assert curVal instanceof Constant || curVal instanceof Local : "these can be produced lazily"; - operand = operandForInstruction(curVal); - } - resolver.move(operand, operandForPhi(phi)); - } - } - } - - private List getPhis(LIRBlock block) { - if (block.getInstructions().size() > 0) { - Node i = block.firstInstruction(); - if (i instanceof Merge) { - List result = new ArrayList(); - for (Node n : i.usages()) { - if (n instanceof Phi) { - result.add((Phi) n); - } - } - return result; - } - } - return null; - } - - protected void moveToPhi() { - // Moves all stack values into their phi position - LIRBlock bb = currentBlock; - if (bb.numberOfSux() == 1) { - LIRBlock sux = bb.suxAt(0); - assert sux.numberOfPreds() > 0 : "invalid CFG"; - - // a block with only one predecessor never has phi functions - if (sux.numberOfPreds() > 1) { - - - List phis = getPhis(sux); - - if (phis != null) { - - int predIndex = 0; - for (; predIndex < sux.numberOfPreds(); ++predIndex) { - if (sux.predAt(predIndex) == bb) { - break; - } - } - assert predIndex < sux.numberOfPreds(); - - PhiResolver resolver = new PhiResolver(this); - for (Phi phi : phis) { - if (!phi.isDead()) { - Value curVal = phi.valueAt(predIndex); - if (curVal != null && curVal != phi) { - if (curVal instanceof Phi) { - operandForPhi((Phi) curVal); - } - CiValue operand = curVal.operand(); - if (operand.isIllegal()) { - assert curVal instanceof Constant || curVal instanceof Local : "these can be produced lazily" + curVal + "/" + phi; - operand = operandForInstruction(curVal); - } - resolver.move(operand, operandForPhi(phi)); - } - } - } - resolver.dispose(); - } - } - } - } - - /** - * Creates a new {@linkplain CiVariable variable}. - * - * @param kind the kind of the variable - * @return a new variable - */ - public CiVariable newVariable(CiKind kind) { - return operands.newVariable(kind); - } - - CiValue operandForInstruction(Value x) { - CiValue operand = x.operand(); - if (operand.isIllegal()) { - if (x instanceof Constant) { - x.setOperand(x.asConstant()); - } else { - assert x instanceof Phi || x instanceof Local : "only for Phi and Local"; - // allocate a variable for this local or phi - createResultVariable(x); - } - } - return x.operand(); - } - - private CiValue operandForPhi(Phi phi) { - assert !phi.isDead() : "dead phi: " + phi.id(); - if (phi.operand().isIllegal()) { - // allocate a variable for this phi - CiVariable operand = newVariable(phi.kind); - setResult(phi, operand); - } - return phi.operand(); - } - - protected void postGCWriteBarrier(CiValue addr, CiValue newVal) { - XirSnippet writeBarrier = xir.genWriteBarrier(toXirArgument(addr)); - if (writeBarrier != null) { - emitXir(writeBarrier, null, null, null, false); - } - } - - protected void preGCWriteBarrier(CiValue addrOpr, boolean patch, LIRDebugInfo info) { - } - - protected void setNoResult(Value x) { - x.clearOperand(); - } - - protected CiValue setResult(Value x, CiVariable operand) { - x.setOperand(operand); - if (C1XOptions.DetailedAsserts) { - operands.recordResult(operand, x); - } - return operand; - } - - protected void shiftOp(int code, CiValue resultOp, CiValue value, CiValue count, CiValue tmp) { - if (isTwoOperand && value != resultOp) { - assert count != resultOp : "malformed"; - lir.move(value, resultOp); - value = resultOp; - } - - assert count.isConstant() || count.isVariableOrRegister(); - switch (code) { - case ISHL: - case LSHL: - lir.shiftLeft(value, count, resultOp, tmp); - break; - case ISHR: - case LSHR: - lir.shiftRight(value, count, resultOp, tmp); - break; - case IUSHR: - case LUSHR: - lir.unsignedShiftRight(value, count, resultOp, tmp); - break; - default: - Util.shouldNotReachHere(); - } - } - - protected void walkState(Node x, FrameState state) { - if (state == null) { - return; - } - for (int index = 0; index < state.stackSize(); index++) { - Value value = state.stackAt(index); - if (value != x) { - walkStateValue(value); - } - } - for (int index = 0; index < state.localsSize(); index++) { - final Value value = state.localAt(index); - if (value != null) { - if (!(value instanceof Phi && ((Phi) value).isDead())) { - walkStateValue(value); - } - } - } - } - - private void walkStateValue(Value value) { - if (value != null) { - if (value instanceof Phi && !((Phi) value).isDead()) { - // phi's are special - operandForPhi((Phi) value); - } else if (value.operand().isIllegal()) { - // instruction doesn't have an operand yet - CiValue operand = makeOperand(value); - assert operand.isLegal() : "must be evaluated now"; - } - } - } - - protected LIRDebugInfo stateFor(Value x) { - assert lastState != null : "must have state before instruction for " + x; - return stateFor(x, lastState); - } - - protected LIRDebugInfo stateFor(Value x, FrameState state) { - if (compilation.placeholderState != null) { - state = compilation.placeholderState; - } - return new LIRDebugInfo(state); - } - - List visitInvokeArguments(CiCallingConvention cc, Invoke x, List pointerSlots) { - // for each argument, load it into the correct location - List argList = new ArrayList(x.argumentCount()); - int j = 0; - for (int i = 0; i < x.argumentCount(); i++) { - Value arg = x.argument(i); - if (arg != null) { - CiValue operand = cc.locations[j++]; - if (operand.isRegister()) { - force(arg, operand); - } else { - LIRItem param = new LIRItem(arg, this); - assert operand.isStackSlot(); - CiStackSlot slot = (CiStackSlot) operand; - assert !slot.inCallerFrame(); - param.loadForStore(slot.kind); - if (slot.kind == CiKind.Long || slot.kind == CiKind.Double) { - lir.unalignedMove(param.result(), slot); - } else { - lir.move(param.result(), slot); - } - - if (arg.kind == CiKind.Object && pointerSlots != null) { - // This slot must be marked explicitly in the pointer map. - pointerSlots.add(slot); - } - } - argList.add(operand); - } - } - return argList; - } - - /** - * Ensures that an operand has been {@linkplain Value#setOperand(CiValue) initialized} - * for storing the result of an instruction. - * - * @param instruction an instruction that produces a result value - */ - protected CiValue makeOperand(Value instruction) { - if (instruction == null) { - return CiValue.IllegalValue; - } - CiValue operand = instruction.operand(); - if (operand.isIllegal()) { - if (instruction instanceof Phi) { - // a phi may not have an operand yet if it is for an exception block - operand = operandForPhi((Phi) instruction); - } else if (instruction instanceof Constant) { - operand = operandForInstruction(instruction); - } - } - // the value must be a constant or have a valid operand - assert operand.isLegal() : "this root has not been visited yet; instruction=" + instruction; - return operand; - } - - /** - * Gets the ABI specific operand used to return a value of a given kind from a method. - * - * @param kind the kind of value being returned - * @return the operand representing the ABI defined location used return a value of kind {@code kind} - */ - protected CiValue resultOperandFor(CiKind kind) { - if (kind == CiKind.Void) { - return IllegalValue; - } - CiRegister returnRegister = compilation.registerConfig.getReturnRegister(kind); - return returnRegister.asValue(kind); - } - - protected XirSupport site(Value x) { - return xirSupport.site(x); - } - - public void maybePrintCurrentInstruction() { - if (currentInstruction != null && lastInstructionPrinted != currentInstruction) { - lastInstructionPrinted = currentInstruction; - InstructionPrinter ip = new InstructionPrinter(TTY.out()); - ip.printInstructionListing(currentInstruction); - } - } - - protected abstract boolean canInlineAsConstant(Value i); - - protected abstract boolean canStoreAsConstant(Value i, CiKind kind); - - protected abstract boolean strengthReduceMultiply(CiValue left, int constant, CiValue result, CiValue tmp); - - protected abstract CiAddress genAddress(CiValue base, CiValue index, int shift, int disp, CiKind kind); - - protected abstract void genCmpMemInt(Condition condition, CiValue base, int disp, int c, LIRDebugInfo info); - - protected abstract void genCmpRegMem(Condition condition, CiValue reg, CiValue base, int disp, CiKind kind, LIRDebugInfo info); - - /** - * Implements site-specific information for the XIR interface. - */ - static class XirSupport implements XirSite { - Value current; - - XirSupport() { - } - - public CiCodePos getCodePos() { - // TODO: get the code position of the current instruction if possible - return null; - } - - public boolean isNonNull(XirArgument argument) { - return false; - } - - public boolean requiresNullCheck() { - return current == null || true; - } - - public boolean requiresBoundsCheck() { - return true; - } - - public boolean requiresReadBarrier() { - return current == null || true; - } - - public boolean requiresWriteBarrier() { - return current == null || true; - } - - public boolean requiresArrayStoreCheck() { - return true; - } - - public RiType getApproximateType(XirArgument argument) { - return current == null ? null : current.declaredType(); - } - - public RiType getExactType(XirArgument argument) { - return current == null ? null : current.exactType(); - } - - XirSupport site(Value v) { - current = v; - return this; - } - - @Override - public String toString() { - return "XirSupport<" + current + ">"; - } - - - } - - @Override - public void visitFrameState(FrameState i) { - // nothing to do for now - } - - @Override - public void visitUnwind(Unwind x) { - // move exception oop into fixed register - CiCallingConvention callingConvention = compilation.frameMap().getCallingConvention(new CiKind[]{CiKind.Object}, RuntimeCall); - CiValue argumentOperand = callingConvention.locations[0]; - lir.move(makeOperand(x.exception()), argumentOperand); - List args = new ArrayList(1); - lir.callRuntime(CiRuntimeCall.UnwindException, CiValue.IllegalValue, args, null); - setNoResult(x); - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/gen/LIRItem.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/gen/LIRItem.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,189 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.gen; - -import com.sun.c1x.alloc.OperandPool.*; -import com.sun.c1x.ir.*; -import com.sun.c1x.util.*; -import com.sun.cri.ci.*; - -/** - * A helper utility for loading the {@linkplain Value#operand() result} - * of an instruction for use by another instruction. This helper takes - * into account the specifics of the consuming instruction such as whether - * it requires the input operand to be in memory or a register, any - * register size requirements of the input operand, and whether the - * usage has the side-effect of overwriting the input operand. To satisfy - * these constraints, an intermediate operand may be created and move - * instruction inserted to copy the output of the producer instruction - * into the intermediate operand. - * - * @author Marcelo Cintra - * @author Thomas Wuerthinger - * @author Doug Simon - */ -public class LIRItem { - - /** - * The instruction whose usage by another instruction is being modeled by this object. - * An instruction {@code x} uses instruction {@code y} if the {@linkplain Value#operand() result} - * of {@code y} is an input operand of {@code x}. - */ - public Value instruction; - - /** - * The LIR context of this helper object. - */ - private final LIRGenerator gen; - - /** - * The operand holding the result of this item's {@linkplain #instruction}. - */ - private CiValue resultOperand; - - /** - * Denotes if the use of the instruction's {@linkplain #resultOperand result operand} - * overwrites the value in the operand. That is, the use both uses and defines the - * operand. In this case, an {@linkplain #intermediateOperand intermediate operand} - * is created for the use so that other consumers of this item's {@linkplain #instruction} - * are not impacted. - */ - private boolean destructive; - - /** - * @see #destructive - */ - private CiValue intermediateOperand; - - public LIRItem(Value instruction, LIRGenerator gen) { - this.gen = gen; - this.instruction = instruction; - resultOperand = gen.makeOperand(instruction); - intermediateOperand = CiValue.IllegalValue; - } - - public void loadForStore(CiKind kind) { - if (gen.canStoreAsConstant(instruction, kind)) { - resultOperand = instruction.operand(); - if (!resultOperand.isConstant()) { - resultOperand = instruction.asConstant(); - } - } else if (kind == CiKind.Byte || kind == CiKind.Boolean) { - loadByteItem(); - } else { - loadItem(); - } - } - - public CiValue result() { - assert !destructive || !resultOperand.isRegister() : "shouldn't use setDestroysRegister with physical registers"; - if (destructive && (resultOperand.isVariable() || resultOperand.isConstant())) { - if (intermediateOperand.isIllegal()) { - intermediateOperand = gen.newVariable(instruction.kind); - gen.lir.move(resultOperand, intermediateOperand); - } - return intermediateOperand; - } else { - return resultOperand; - } - } - - public void setDestroysRegister() { - destructive = true; - } - - /** - * Determines if the operand is in a stack slot. - */ - public boolean isStack() { - return resultOperand.isAddress() || resultOperand.isStackSlot(); - } - - /** - * Determines if the operand is in a register or may be - * resolved to a register by the register allocator. - */ - public boolean isRegisterOrVariable() { - return resultOperand.isVariableOrRegister(); - } - - public void loadByteItem() { - if (gen.compilation.target.arch.isX86()) { - loadItem(); - CiValue res = result(); - - if (!res.isVariable() || !gen.operands.mustBeByteRegister(res)) { - // make sure that it is a byte register - assert !instruction.kind.isFloat() && !instruction.kind.isDouble() : "can't load floats in byte register"; - CiValue reg = gen.operands.newVariable(CiKind.Byte, VariableFlag.MustBeByteRegister); - gen.lir.move(res, reg); - resultOperand = reg; - } - } else if (gen.compilation.target.arch.isSPARC()) { - loadItem(); - } else { - Util.shouldNotReachHere(); - } - } - - public void loadNonconstant() { - assert gen.compilation.target.arch.isX86(); - CiValue r = instruction.operand(); - if (r.isConstant()) { - resultOperand = r; - } else { - loadItem(); - } - } - - private void setResult(CiVariable operand) { - gen.setResult(instruction, operand); - resultOperand = operand; - } - - /** - * Creates an operand containing the result of {@linkplain #instruction input instruction}. - */ - public void loadItem() { - if (result().isIllegal()) { - // update the item's result - resultOperand = instruction.operand(); - } - CiValue result = result(); - if (!result.isVariableOrRegister()) { - CiVariable operand; - operand = gen.newVariable(instruction.kind); - gen.lir.move(result, operand); - if (result.isConstant()) { - resultOperand = operand; - } else { - setResult(operand); - } - } - } - - @Override - public String toString() { - return result().toString(); - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/gen/PhiResolver.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/gen/PhiResolver.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,238 +0,0 @@ -/* - * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.gen; - -import static com.sun.cri.ci.CiValue.*; - -import java.util.*; - -import com.sun.c1x.ir.*; -import com.sun.cri.ci.*; - -/** - * Converts {@link Phi} instructions into moves. - * - * Resolves cycles: - *
- *
- *  r1 := r2  becomes  temp := r1
- *  r2 := r1           r1 := r2
- *                     r2 := temp
- * 
- * - * and orders moves: - * - *
- *  r2 := r3  becomes  r1 := r2
- *  r1 := r2           r2 := r3
- * 
- * - * @author Marcelo Cintra - * @author Thomas Wuerthinger - * @author Doug Simon - */ -public class PhiResolver { - - /** - * Tracks a data flow dependency between a source operand and any number of the destination operands. - */ - static class Node { - - /** - * A source operand whose value flows into the {@linkplain #destinations destination} operands. - */ - final CiValue operand; - - /** - * The operands whose values are defined by the {@linkplain #operand source} operand. - */ - final ArrayList destinations; - - /** - * Denotes if a move instruction has already been emitted to initialize the value of {@link #operand}. - */ - boolean assigned; - - /** - * Specifies if this operand been visited for the purpose of emitting a move instruction. - */ - boolean visited; - - /** - * Specifies if this is the initial definition in data flow path for a given value. - */ - boolean startNode; - - Node(CiValue operand) { - this.operand = operand; - destinations = new ArrayList(4); - } - - @Override - public String toString() { - StringBuilder buf = new StringBuilder(operand.toString()); - if (!destinations.isEmpty()) { - buf.append(" ->"); - for (Node node : destinations) { - buf.append(' ').append(node.operand); - } - } - return buf.toString(); - } - } - - private final LIRGenerator gen; - - /** - * The operand loop header phi for the operand currently being process in {@link #dispose()}. - */ - private Node loop; - - private CiValue temp; - - private final ArrayList variableOperands = new ArrayList(3); - private final ArrayList otherOperands = new ArrayList(3); - - /** - * Maps operands to nodes. - */ - private final HashMap operandToNodeMap = new HashMap(); - - public PhiResolver(LIRGenerator gen) { - this.gen = gen; - temp = IllegalValue; - } - - public void dispose() { - // resolve any cycles in moves from and to variables - for (int i = variableOperands.size() - 1; i >= 0; i--) { - Node node = variableOperands.get(i); - if (!node.visited) { - loop = null; - move(null, node); - node.startNode = true; - assert temp.isIllegal() : "moveTempTo() call missing"; - } - } - - // generate move for move from non variable to arbitrary destination - for (int i = otherOperands.size() - 1; i >= 0; i--) { - Node node = otherOperands.get(i); - for (int j = node.destinations.size() - 1; j >= 0; j--) { - emitMove(node.operand, node.destinations.get(j).operand); - } - } - } - - public void move(CiValue src, CiValue dest) { - assert dest.isVariable() : "destination must be virtual"; - // tty.print("move "); src.print(); tty.print(" to "); dest.print(); tty.cr(); - assert src.isLegal() : "source for phi move is illegal"; - assert dest.isLegal() : "destination for phi move is illegal"; - Node srcNode = sourceNode(src); - Node destNode = destinationNode(dest); - srcNode.destinations.add(destNode); - } - - private Node createNode(CiValue operand, boolean source) { - Node node; - if (operand.isVariable()) { - node = operandToNodeMap.get(operand); - assert node == null || node.operand.equals(operand); - if (node == null) { - node = new Node(operand); - operandToNodeMap.put(operand, node); - } - // Make sure that all variables show up in the list when - // they are used as the source of a move. - if (source) { - if (!variableOperands.contains(node)) { - variableOperands.add(node); - } - } - } else { - assert source; - node = new Node(operand); - otherOperands.add(node); - } - return node; - } - - private Node destinationNode(CiValue opr) { - return createNode(opr, false); - } - - private void emitMove(CiValue src, CiValue dest) { - assert src.isLegal(); - assert dest.isLegal(); - gen.lir.move(src, dest); - } - - // Traverse assignment graph in depth first order and generate moves in post order - // ie. two assignments: b := c, a := b start with node c: - // Call graph: move(NULL, c) -> move(c, b) -> move(b, a) - // Generates moves in this order: move b to a and move c to b - // ie. cycle a := b, b := a start with node a - // Call graph: move(NULL, a) -> move(a, b) -> move(b, a) - // Generates moves in this order: move b to temp, move a to b, move temp to a - private void move(Node src, Node dest) { - if (!dest.visited) { - dest.visited = true; - for (int i = dest.destinations.size() - 1; i >= 0; i--) { - move(dest, dest.destinations.get(i)); - } - } else if (!dest.startNode) { - // cycle in graph detected - assert loop == null : "only one loop valid!"; - loop = dest; - moveToTemp(src.operand); - return; - } // else dest is a start node - - if (!dest.assigned) { - if (loop == dest) { - moveTempTo(dest.operand); - dest.assigned = true; - } else if (src != null) { - emitMove(src.operand, dest.operand); - dest.assigned = true; - } - } - } - - private void moveTempTo(CiValue dest) { - assert temp.isLegal(); - emitMove(temp, dest); - temp = IllegalValue; - } - - private void moveToTemp(CiValue src) { - assert temp.isIllegal(); - temp = gen.newVariable(src.kind); - emitMove(src, temp); - } - - private Node sourceNode(CiValue opr) { - return createNode(opr, true); - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/gen/PhiSimplifier.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/gen/PhiSimplifier.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,119 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.gen; - -import com.oracle.graal.graph.*; -import com.sun.c1x.ir.*; - -/** - * The {@code PhiSimplifier} class is a helper class that can reduce phi instructions. - */ -public final class PhiSimplifier { - - private NodeBitMap visited; - private NodeBitMap cannotSimplify; - - public PhiSimplifier(Graph graph) { - visited = graph.createNodeBitMap(); - cannotSimplify = graph.createNodeBitMap(); - - for (Node n : graph.getNodes()) { - if (n instanceof Phi) { - simplify((Phi) n); - } - } - } - - private Value simplify(Value x) { - if (x == null || !(x instanceof Phi)) { - return x; - } - Phi phi = (Phi) x; - - if (phi.valueCount() == 1 && !cannotSimplify.isMarked(phi)) { - return (Value) phi.replace(phi.valueAt(0)); - } - - if (cannotSimplify.isMarked(phi)) { - // already tried, cannot simplify this phi - return phi; - } else if (visited.isMarked(phi)) { - // break cycles in phis - return phi; - } else if (phi.isDead()) { - // don't bother with illegals - return phi; - } else { - // attempt to simplify the phi by recursively simplifying its operands - visited.mark(phi); - Value phiSubst = null; - int max = phi.valueCount(); - boolean cannotSimplify = false; - for (int i = 0; i < max; i++) { - Value oldInstr = phi.valueAt(i); - - if (oldInstr == null || (oldInstr instanceof Phi && ((Phi) oldInstr).isDead())) { - // if one operand is illegal, make the entire phi illegal - phi.makeDead(); - visited.clear(phi); - return phi; - } - - Value newInstr = simplify(oldInstr); - - if (newInstr == null || (newInstr instanceof Phi && ((Phi) newInstr).isDead())) { - // if the subst instruction is illegal, make the entire phi illegal - phi.makeDead(); - visited.clear(phi); - return phi; - } - - // attempt to simplify this operand - if (!cannotSimplify) { - - if (newInstr != phi && newInstr != phiSubst) { - if (phiSubst == null) { - phiSubst = newInstr; - continue; - } - // this phi cannot be simplified - cannotSimplify = true; - } - } - } - if (cannotSimplify) { - this.cannotSimplify.mark(phi); - visited.clear(phi); - return phi; - } - - // successfully simplified the phi - assert phiSubst != null : "illegal phi function"; - visited.clear(phi); - - phi.replace(phiSubst); - - return phiSubst; - } - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/gen/package-info.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/gen/package-info.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -/** - * This package contains the port of the LIRGenerator which translates - * HIR instructions to LIR instructions for the backend. - * - * @author Marcelo Cintra - * @author Thomas Wuerthinger - */ -package com.sun.c1x.gen; diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/globalstub/GlobalStub.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/globalstub/GlobalStub.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,76 +0,0 @@ -/* - * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.globalstub; - -import static com.sun.cri.ci.CiKind.*; - -import com.sun.cri.ci.*; - -/** - * A global stub is a shared routine that performs an operation on behalf of compiled code. - * Typically the routine is too large to inline, is infrequent, or requires runtime support. - * Global stubs are called with a callee-save convention; the global stub must save any - * registers it may destroy and then restore them upon return. This allows the register - * allocator to ignore calls to global stubs. Parameters to global stubs are - * passed on the stack in order to preserve registers for the rest of the code. - * - * @author Thomas Wuerthinger - * @author Ben L. Titzer - */ -public class GlobalStub { - - public enum Id { - - fneg(Float, Float), - dneg(Double, Double), - f2i(Int, Float), - f2l(Long, Float), - d2i(Int, Double), - d2l(Long, Double); - - public final CiKind resultKind; - public final CiKind[] arguments; - - private Id(CiKind resultKind, CiKind... args) { - this.resultKind = resultKind; - this.arguments = args; - } - } - - public final Id id; - public final CiKind resultKind; - public final Object stubObject; - public final int argsSize; - public final int[] argOffsets; - public final int resultOffset; - - public GlobalStub(Id id, CiKind resultKind, Object stubObject, int argsSize, int[] argOffsets, int resultOffset) { - this.id = id; - this.resultKind = resultKind; - this.stubObject = stubObject; - this.argsSize = argsSize; - this.argOffsets = argOffsets; - this.resultOffset = resultOffset; - } - -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/globalstub/GlobalStubEmitter.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/globalstub/GlobalStubEmitter.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.globalstub; - -import com.sun.cri.ci.*; -import com.sun.cri.ri.*; -import com.sun.cri.xir.*; - -/** - * An interface to represent the entity that generates stubs. - * - * @author Thomas Wuerthinger - * @author Ben L. Titzer - */ -public interface GlobalStubEmitter { - GlobalStub emit(GlobalStub.Id stub, RiRuntime runtime); - GlobalStub emit(CiRuntimeCall runtimeCall, RiRuntime runtime); - GlobalStub emit(XirTemplate t, RiRuntime runtime); -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/graph/BlockMap.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/graph/BlockMap.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,664 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.graph; - -import static com.sun.cri.bytecode.Bytecodes.*; - -import java.util.*; - -import com.sun.c1x.debug.*; -import com.sun.c1x.ir.*; -import com.sun.cri.bytecode.*; -import com.sun.cri.ci.*; -import com.sun.cri.ri.*; - -/** - * Builds a mapping between bytecodes and basic blocks and builds a conservative control flow - * graph. Note that this class serves a similar role to C1's {@code BlockListBuilder}, but makes fewer assumptions about - * what the compiler interface provides. It builds all basic blocks for the control flow graph without requiring the - * compiler interface to provide a bitmap of the beginning of basic blocks. It makes two linear passes; one over the - * bytecodes to build block starts and successor lists, and one pass over the block map to build the CFG. - * - * Note that the CFG built by this class is not connected to the actual {@code BlockBegin} instances; this class - * does, however, compute and assign the reverse postorder number of the blocks. This comment needs refinement. (MJJ) - * - *

More Details on {@link BlockMap#build}

- * - * If the method has any exception handlers the {@linkplain #exceptionMap exception map} will be created (TBD). - * - * The bytecodes are then scanned linearly looking for bytecodes that contain control transfers, e.g., {@code GOTO}, - * {@code RETURN}, {@code IFGE}, and creating the corresponding entries in {@link #successorMap} and {@link #blockMap}. - * In addition, if {@link #exceptionMap} is not null, entries are made for any bytecode that can cause an exception. - * More TBD. - * - * Observe that this process finds bytecodes that terminate basic blocks, so the {@link #moveSuccessorLists} method is - * called to reassign the successors to the {@code BlockBegin} node that actually starts the block. - * - *

Example

- * - * Consider the following source code: - * - *
- * 
- *     public static int test(int arg1, int arg2) {
- *         int x = 0;
- *         while (arg2 > 0) {
- *             if (arg1 > 0) {
- *                 x += 1;
- *             } else if (arg1 < 0) {
- *                 x -= 1;
- *             }
- *         }
- *         return x;
- *     }
- * 
- * 
- * - * This is translated by javac to the following bytecode: - * - *
- * 
- *    0:   iconst_0
- *    1:   istore_2
- *    2:   goto    22
- *    5:   iload_0
- *    6:   ifle    15
- *    9:   iinc    2, 1
- *    12:  goto    22
- *    15:  iload_0
- *    16:  ifge    22
- *    19:  iinc    2, -1
- *    22:  iload_1
- *    23:  ifgt    5
- *    26:  iload_2
- *    27:  ireturn
- *    
- * 
- * - * There are seven basic blocks in this method, 0..2, 5..6, 9..12, 15..16, 19..19, 22..23 and 26..27. Therefore, before - * the call to {@code moveSuccessorLists}, the {@code blockMap} array has {@code BlockBegin} nodes at indices 0, 5, 9, - * 15, 19, 22 and 26. The {@code successorMap} array has entries at 2, 6, 12, 16, 23, 27 corresponding to the control - * transfer bytecodes. The entry at index 6, for example, is a length two array of {@code BlockBegin} nodes for indices - * 9 and 15, which are the successors for the basic block 5..6. After the call to {@code moveSuccessors}, {@code - * successorMap} has entries at 0, 5, 9, 15, 19, 22 and 26, i.e, matching {@code blockMap}. - *

- * Next the blocks are numbered using reverse - * post-order. For the above example this results in the numbering 2, 4, 7, 5, 6, 3, 8. Also loop header blocks are - * detected during the traversal by detecting a repeat visit to a block that is still being processed. This causes the - * block to be flagged as a loop header and also added to the {@link #loopBlocks} list. The {@code loopBlocks} list - * contains the blocks at 0, 5, 9, 15, 19, 22, with 22 as the loop header. (N.B. the loop header block is added multiple - * (4) times to this list). (Should 0 be in? It's not inside the loop). - * - * If the {@code computeStoresInLoops} argument to {@code build} is true, the {@code loopBlocks} list is processed to - * mark all local variables that are stored in the blocks in the list. - */ -public final class BlockMap { - public static class Block { - public int startBci; - public int endBci; - public boolean isExceptionEntry; - public boolean isLoopHeader; - public int blockID; - - public Instruction firstInstruction; - - final HashSet successors = new HashSet(); - private boolean visited; - private boolean active; - private int loops; - } - - public static class ExceptionBlock extends Block { - public RiExceptionHandler handler; - public Block next; - } - - private static final Block[] NO_SUCCESSORS = new Block[0]; - - /** - * The blocks found in this method, in reverse postorder. - */ - public final List blocks; - - /** - * A bit map covering the locals with a bit set for each local that might be stored to within a - * loop. If the bit is cleared, it is guaranteed that the local is never stored in a loop. - */ - public final BitSet storesInLoops; - - private final RiMethod method; - - private Block[] blockMap; - - private BitSet canTrap; - - /** - * Creates a new BlockMap instance from bytecode of the given method . - * @param method the compiler interface method containing the code - */ - public BlockMap(RiMethod method) { - this.method = method; - this.blockMap = new Block[method.code().length]; - if (method.exceptionHandlers().length != 0) { - this.canTrap = new BitSet(blockMap.length); - } - this.blocks = new ArrayList(); - this.storesInLoops = new BitSet(method.maxLocals()); - } - - /** - * Builds the block map and conservative CFG and numbers blocks. - */ - public void build() { - makeExceptionEntries(); - iterateOverBytecodes(); - addExceptionEdges(); - computeBlockOrder(); - - initializeBlockIds(); - - // Discard big arrays so that they can be GCed - blockMap = null; - canTrap = null; - } - - private void initializeBlockIds() { - for (int i = 0; i < blocks.size(); i++) { - blocks.get(i).blockID = i; - } - } - - private void makeExceptionEntries() { - // start basic blocks at all exception handler blocks and mark them as exception entries - for (RiExceptionHandler h : method.exceptionHandlers()) { - Block xhandler = makeBlock(h.handlerBCI()); - xhandler.isExceptionEntry = true; - } - } - - private void iterateOverBytecodes() { - // iterate over the bytecodes top to bottom. - // mark the entrypoints of basic blocks and build lists of successors for - // all bytecodes that end basic blocks (i.e. goto, ifs, switches, throw, jsr, returns, ret) - byte[] code = method.code(); - Block current = null; - int bci = 0; - while (bci < code.length) { - if (current == null || blockMap[bci] != null) { - Block b = makeBlock(bci); - if (current != null) { - setSuccessors(current.endBci, b); - } - current = b; - } - blockMap[bci] = current; - current.endBci = bci; - - int opcode = Bytes.beU1(code, bci); - switch (opcode) { - case IRETURN: // fall through - case LRETURN: // fall through - case FRETURN: // fall through - case DRETURN: // fall through - case ARETURN: // fall through - case WRETURN: // fall through - case RETURN: { - current = null; - - assert lengthOf(code, bci) == 1; - bci += 1; - break; - } - - case ATHROW: { - current = null; - if (canTrap != null) { - canTrap.set(bci); - } - - assert lengthOf(code, bci) == 1; - bci += 1; - break; - } - - case IFEQ: // fall through - case IFNE: // fall through - case IFLT: // fall through - case IFGE: // fall through - case IFGT: // fall through - case IFLE: // fall through - case IF_ICMPEQ: // fall through - case IF_ICMPNE: // fall through - case IF_ICMPLT: // fall through - case IF_ICMPGE: // fall through - case IF_ICMPGT: // fall through - case IF_ICMPLE: // fall through - case IF_ACMPEQ: // fall through - case IF_ACMPNE: // fall through - case IFNULL: // fall through - case IFNONNULL: { - current = null; - Block b1 = makeBlock(bci + 3); - Block b2 = makeBlock(bci + Bytes.beS2(code, bci + 1)); - setSuccessors(bci, b1, b2); - - assert lengthOf(code, bci) == 3; - bci += 3; - break; - } - - case GOTO: { - current = null; - Block b1 = makeBlock(bci + Bytes.beS2(code, bci + 1)); - setSuccessors(bci, b1); - - assert lengthOf(code, bci) == 3; - bci += 3; - break; - } - - case GOTO_W: { - current = null; - Block b1 = makeBlock(bci + Bytes.beS4(code, bci + 1)); - setSuccessors(bci, b1); - - assert lengthOf(code, bci) == 5; - bci += 5; - break; - } - - case TABLESWITCH: { - BytecodeTableSwitch sw = new BytecodeTableSwitch(code, bci); - setSuccessors(bci, makeSwitchSuccessors(sw)); - current = null; - - assert lengthOf(code, bci) == sw.size(); - bci += sw.size(); - break; - } - - case LOOKUPSWITCH: { - current = null; - BytecodeLookupSwitch sw = new BytecodeLookupSwitch(code, bci); - setSuccessors(bci, makeSwitchSuccessors(sw)); - - assert lengthOf(code, bci) == sw.size(); - bci += sw.size(); - break; - } - - case JSR: { - throw new JSRNotSupportedBailout(); - } - case JSR_W: { - throw new JSRNotSupportedBailout(); - } - case RET: { - throw new JSRNotSupportedBailout(); - } - - case WIDE: { - bci += lengthOf(code, bci); - break; - } - - default: { - if (canTrap != null && canTrap(opcode)) { - canTrap.set(bci); - } - - assert lengthOf(code, bci) == lengthOf(opcode); - bci += lengthOf(opcode); - } - } - } - } - - public static boolean canTrap(int opcode) { - switch (opcode) { - case INVOKESTATIC: - case INVOKESPECIAL: - case INVOKEVIRTUAL: - case INVOKEINTERFACE: { - return true; - } - } - return false; - } - - private Block makeBlock(int startBci) { - Block oldBlock = blockMap[startBci]; - if (oldBlock == null) { - Block newBlock = new Block(); - newBlock.startBci = startBci; - blockMap[startBci] = newBlock; - return newBlock; - - } else if (oldBlock.startBci != startBci) { - // Backward branch into the middle of an already processed block. - // Add the correct fall-through successor. - Block newBlock = new Block(); - newBlock.startBci = startBci; - newBlock.endBci = oldBlock.endBci; - newBlock.successors.addAll(oldBlock.successors); - - oldBlock.endBci = startBci - 1; - oldBlock.successors.clear(); - oldBlock.successors.add(newBlock); - - for (int i = startBci; i <= newBlock.endBci; i++) { - blockMap[i] = newBlock; - } - return newBlock; - - } else { - return oldBlock; - } - } - - private Block[] makeSwitchSuccessors(BytecodeSwitch tswitch) { - int max = tswitch.numberOfCases(); - Block[] successors = new Block[max + 1]; - for (int i = 0; i < max; i++) { - successors[i] = makeBlock(tswitch.targetAt(i)); - } - successors[max] = makeBlock(tswitch.defaultTarget()); - return successors; - } - - private void setSuccessors(int predBci, Block... successors) { - for (Block sux : successors) { - if (sux.isExceptionEntry) { - throw new CiBailout("Exception handler can be reached by both normal and exceptional control flow"); - } - } - Block predecessor = blockMap[predBci]; - assert predecessor.successors.size() == 0; - predecessor.successors.addAll(Arrays.asList(successors)); - } - - private HashMap exceptionDispatch = new HashMap(); - - private ExceptionBlock unwindBlock; - - private Block makeExceptionDispatch(List handlers, int index) { - RiExceptionHandler handler = handlers.get(index); - if (handler.isCatchAll()) { - return blockMap[handler.handlerBCI()]; - } - ExceptionBlock block = exceptionDispatch.get(handler); - if (block == null) { - block = new ExceptionBlock(); - block.startBci = -1; - block.endBci = -1; - block.handler = handler; - block.successors.add(blockMap[handler.handlerBCI()]); - if (index < handlers.size() - 1) { - block.next = makeExceptionDispatch(handlers, index + 1); - block.successors.add(block.next); - } - exceptionDispatch.put(handler, block); - } - return block; - } - - private void addExceptionEdges() { - if (canTrap == null) { - return; - } - - for (int bci = canTrap.nextSetBit(0); bci >= 0; bci = canTrap.nextSetBit(bci + 1)) { - Block block = blockMap[bci]; - - ArrayList handlers = null; - for (RiExceptionHandler h : method.exceptionHandlers()) { - if (h.startBCI() <= bci && bci < h.endBCI()) { - if (handlers == null) { - handlers = new ArrayList(); - } - handlers.add(h); - if (h.isCatchAll()) { - break; - } - } - } - if (handlers != null) { - Block dispatch = makeExceptionDispatch(handlers, 0); - block.successors.add(dispatch); - } - } - } - - private void computeBlockOrder() { - int loop = computeBlockOrder(blockMap[0]); - - if (loop != 0) { - // There is a path from a loop end to the method entry that does not pass the loop header. - // Therefore, the loop is non reducible (has more than one entry). - // We don't want to compile such methods because the IR only supports structured loops. - throw new CiBailout("Non-reducible loop"); - } - - // Convert postorder to the desired reverse postorder. - Collections.reverse(blocks); - } - - /** - * The next available loop number. - */ - private int nextLoop = 0; - - /** - * Mark the block as a loop header, using the next available loop number. - * Also checks for corner cases that we don't want to compile. - */ - private void makeLoopHeader(Block block) { - if (!block.isLoopHeader) { - block.isLoopHeader = true; - - if (block.isExceptionEntry) { - // Loops that are implicitly formed by an exception handler lead to all sorts of corner cases. - // Don't compile such methods for now, until we see a concrete case that allows checking for correctness. - throw new CiBailout("Loop formed by an exception handler"); - } - if (nextLoop >= Integer.SIZE) { - // This restriction can be removed by using a fall-back to a BitSet in case we have more than 32 loops - // Don't compile such methods for now, until we see a concrete case that allows checking for correctness. - throw new CiBailout("Too many loops in method"); - } - - assert block.loops == 0; - block.loops = 1 << nextLoop; - nextLoop++; - } - assert Integer.bitCount(block.loops) == 1; - } - - /** - * Depth-first traversal of the control flow graph. The flag {@linkplain Block#visited} is used to - * visit every block only once. The flag {@linkplain Block#active} is used to detect cycles (backward - * edges). - */ - private int computeBlockOrder(Block block) { - if (block.visited) { - if (block.active) { - // Reached block via backward branch. - makeLoopHeader(block); - } - // Return cached loop information for this block. - return block.loops; - } - - block.visited = true; - block.active = true; - - int loops = 0; - for (Block successor : block.successors) { - // Recursively process successors. - loops |= computeBlockOrder(successor); - } - - if (loops != 0) { - processLoopBlock(block); - } - if (block.isLoopHeader) { - assert Integer.bitCount(block.loops) == 1; - loops &= ~block.loops; - } - - block.loops = loops; - block.active = false; - blocks.add(block); - - return loops; - } - - private void processLoopBlock(Block block) { - // process all the stores in this block - byte[] code = method.code(); - int bci = block.startBci; - if (bci >= 0) { - while (bci <= block.endBci) { - int opcode = Bytes.beU1(code, bci); - if (isStore(opcode)) { - processStore(opcode, Bytes.beU1(code, bci + 1)); - - } else if (opcode == WIDE) { - opcode = Bytes.beU1(code, bci + 1); - if (isStore(opcode)) { - processStore(opcode, Bytes.beU2(code, bci + 2)); - } - } - bci += lengthOf(code, bci); - } - } - } - - private void processStore(int opcode, int local) { - switch (opcode) { - case IINC: - case ISTORE: - case FSTORE: - case WSTORE: - case ASTORE: - storesInLoops.set(local); - break; - - case LSTORE: - case DSTORE: - storesInLoops.set(local); - storesInLoops.set(local + 1); - break; - - case ISTORE_0: - case FSTORE_0: - case ASTORE_0: - case WSTORE_0: - storesInLoops.set(0); - break; - case ISTORE_1: - case FSTORE_1: - case ASTORE_1: - case WSTORE_1: - storesInLoops.set(1); - break; - case ISTORE_2: - case FSTORE_2: - case ASTORE_2: - case WSTORE_2: - storesInLoops.set(2); - break; - case ISTORE_3: - case FSTORE_3: - case ASTORE_3: - case WSTORE_3: - storesInLoops.set(3); - break; - - case LSTORE_0: - case DSTORE_0: - storesInLoops.set(0); - storesInLoops.set(1); - break; - case LSTORE_1: - case DSTORE_1: - storesInLoops.set(1); - storesInLoops.set(2); - break; - case LSTORE_2: - case DSTORE_2: - storesInLoops.set(2); - storesInLoops.set(3); - break; - case LSTORE_3: - case DSTORE_3: - storesInLoops.set(3); - storesInLoops.set(4); - break; - - default: - throw new InternalError("undefined store bytecode"); - } - } - - - - /** - * Print block information in the format required by {@linkplain CFGPrinter}. The method must - * be here because it accesses private state of a block. - */ - public void printBlock(Block block, LogStream out) { - out.print("name \"B").print(block.startBci).println('"'); - out.print("from_bci ").println(block.startBci); - out.print("to_bci ").println(block.endBci); - - out.println("predecessors "); - - out.print("successors "); - for (Block succ : block.successors) { - if (!succ.isExceptionEntry) { - out.print("\"B").print(succ.startBci).print("\" "); - } - } - out.println(); - - out.print("xhandlers"); - for (Block succ : block.successors) { - if (succ.isExceptionEntry) { - out.print("\"B").print(succ.startBci).print("\" "); - } - } - out.println(); - - out.print("flags "); - if (block.isExceptionEntry) { - out.print("\"ex\" "); - } - if (block.isLoopHeader) { - out.print("\"plh\" "); - } - out.println(); - - out.print("loop_depth ").println(Integer.bitCount(block.loops)); - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/graph/CompilerGraph.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/graph/CompilerGraph.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.graph; - -import com.oracle.graal.graph.*; -import com.sun.c1x.ir.*; - - -public class CompilerGraph extends Graph { - - private Return returnSingleton; - private Unwind unwindSingleton; - - public Return createReturn(Value result) { - assert returnSingleton == null; - returnSingleton = new Return(result, this); - return returnSingleton; - } - - public Return getReturn() { - return returnSingleton; - } - - public Unwind createUnwind(Value exception) { - assert unwindSingleton == null; - unwindSingleton = new Unwind(exception, this); - return unwindSingleton; - } - - public Unwind getUnwind() { - return unwindSingleton; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/graph/DeadCodeElimination.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/graph/DeadCodeElimination.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,133 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.graph; - -import com.oracle.graal.graph.*; -import com.sun.c1x.*; -import com.sun.c1x.gen.*; -import com.sun.c1x.ir.*; - - -public class DeadCodeElimination extends Phase { - - private NodeBitMap alive; - private NodeWorklist worklist; - private Graph graph; - - public int deletedNodeCount; - - @Override - protected void run(Graph graph) { - this.graph = graph; - this.alive = graph.createNodeBitMap(); - this.worklist = graph.createNodeWorklist(); - - worklist.add(graph.start()); - - iterateSuccessors(); - disconnectCFGNodes(); - - iterateInputs(); - disconnectNonCFGNodes(); - - deleteCFGNodes(); - deleteNonCFGNodes(); - - new PhiSimplifier(graph); - - if (C1XOptions.TraceDeadCodeElimination) { - System.out.printf("dead code elimination: deleted %d nodes\n", deletedNodeCount); - } - } - - private static boolean isCFG(Node n) { - return n != null && ((n instanceof Instruction) || n == n.graph().start()); - } - - private void iterateSuccessors() { - for (Node current : worklist) { - for (Node successor : current.successors()) { - worklist.add(successor); - } - } - } - - private void disconnectCFGNodes() { - for (Node node : graph.getNodes()) { - if (node != Node.Null && !worklist.isMarked(node) && isCFG(node)) { - // iterate backwards so that the predecessor indexes in removePhiPredecessor are correct - for (int i = node.successors().size() - 1; i >= 0; i--) { - Node successor = node.successors().get(i); - if (successor != Node.Null && worklist.isMarked(successor)) { - if (successor instanceof Merge) { - ((Merge) successor).removePhiPredecessor(node); - } - } - } - node.successors().clearAll(); - node.inputs().clearAll(); - } - } - } - - private void deleteCFGNodes() { - for (Node node : graph.getNodes()) { - if (node != Node.Null && !worklist.isMarked(node) && isCFG(node)) { - node.delete(); - deletedNodeCount++; - } - } - } - - private void iterateInputs() { - for (Node node : graph.getNodes()) { - if (node != Node.Null && worklist.isMarked(node)) { - for (Node input : node.inputs()) { - worklist.add(input); - } - } - } - for (Node current : worklist) { - for (Node input : current.inputs()) { - worklist.add(input); - } - } - } - - private void disconnectNonCFGNodes() { - for (Node node : graph.getNodes()) { - if (node != Node.Null && !worklist.isMarked(node) && !isCFG(node)) { - node.inputs().clearAll(); - } - } - } - - private void deleteNonCFGNodes() { - for (Node node : graph.getNodes()) { - if (node != Node.Null && !worklist.isMarked(node) && !isCFG(node)) { - node.delete(); - deletedNodeCount++; - } - } - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/graph/GraphBuilder.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/graph/GraphBuilder.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1521 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.graph; - -import static com.sun.cri.bytecode.Bytecodes.*; -import static java.lang.reflect.Modifier.*; - -import java.lang.reflect.*; -import java.util.*; - -import com.oracle.graal.graph.*; -import com.oracle.max.graal.schedule.*; -import com.sun.c1x.*; -import com.sun.c1x.debug.*; -import com.sun.c1x.graph.BlockMap.*; -import com.sun.c1x.graph.BlockMap.Block; -import com.sun.c1x.ir.*; -import com.sun.c1x.util.*; -import com.sun.c1x.value.*; -import com.sun.cri.bytecode.*; -import com.sun.cri.ci.*; -import com.sun.cri.ri.*; -import com.sun.cri.ri.RiType.*; - -/** - * The {@code GraphBuilder} class parses the bytecode of a method and builds the IR graph. - * A number of optimizations may be performed during parsing of the bytecode, including value - * numbering, inlining, constant folding, strength reduction, etc. - */ -public final class GraphBuilder { - - /** - * The minimum value to which {@link C1XOptions#TraceBytecodeParserLevel} must be set to trace - * the bytecode instructions as they are parsed. - */ - public static final int TRACELEVEL_INSTRUCTIONS = 1; - - /** - * The minimum value to which {@link C1XOptions#TraceBytecodeParserLevel} must be set to trace - * the frame state before each bytecode instruction as it is parsed. - */ - public static final int TRACELEVEL_STATE = 2; - - private final C1XCompilation compilation; - private final CompilerGraph graph; - - private final CiStatistics stats; - private final RiRuntime runtime; - private final RiMethod method; - private final RiConstantPool constantPool; - - private final BytecodeStream stream; // the bytecode stream - private final LogStream log; - private final FrameStateBuilder frameState; // the current execution state - - // bci-to-block mapping - private Block[] blockFromBci; - private ArrayList blockList; - - private int nextBlockNumber; - - private Value methodSynchronizedObject; - private CiExceptionHandler syncHandler; - - private Block unwindBlock; - private Block returnBlock; - - // the worklist of blocks, sorted by depth first number - private final PriorityQueue workList = new PriorityQueue(10, new Comparator() { - public int compare(Block o1, Block o2) { - return o1.blockID - o2.blockID; - } - }); - - private Instruction lastInstr; // the last instruction added - - private final Set blocksOnWorklist = new HashSet(); - private final Set blocksVisited = new HashSet(); - - - /** - * Creates a new, initialized, {@code GraphBuilder} instance for a given compilation. - * - * @param compilation the compilation - * @param ir the IR to build the graph into - * @param graph - */ - public GraphBuilder(C1XCompilation compilation, RiMethod method, CompilerGraph graph) { - this.compilation = compilation; - this.graph = graph; - - this.runtime = compilation.runtime; - this.method = method; - this.stats = compilation.stats; - this.log = C1XOptions.TraceBytecodeParserLevel > 0 ? new LogStream(TTY.out()) : null; - this.stream = new BytecodeStream(method.code()); - - this.constantPool = runtime.getConstantPool(method); - this.frameState = new FrameStateBuilder(method, graph); - } - - /** - * Builds the graph for a the specified {@code IRScope}. - * - * @param createUnwind setting this to true will always generate an unwind block, even if there is no exception - * handler and the method is not synchronized - */ - public void build(boolean createUnwind) { - if (log != null) { - log.println(); - log.println("Compiling " + method); - } - - // 2. compute the block map, setup exception handlers and get the entrypoint(s) - BlockMap blockMap = compilation.getBlockMap(method); - - blockList = new ArrayList(blockMap.blocks); - blockFromBci = new Block[method.code().length]; - for (int i = 0; i < blockList.size(); i++) { - int blockID = nextBlockNumber(); - assert blockID == i; - Block block = blockList.get(i); - if (block.startBci >= 0) { - blockFromBci[block.startBci] = block; - } - } - - // 1. create the start block - Block startBlock = nextBlock(Instruction.SYNCHRONIZATION_ENTRY_BCI); - markOnWorkList(startBlock); - lastInstr = createTarget(startBlock, frameState); - graph.start().setStart(lastInstr); - - if (isSynchronized(method.accessFlags())) { - // 4A.1 add a monitor enter to the start block - methodSynchronizedObject = synchronizedObject(frameState, method); - genMonitorEnter(methodSynchronizedObject, Instruction.SYNCHRONIZATION_ENTRY_BCI); - // 4A.2 finish the start block - finishStartBlock(startBlock); - - // 4A.3 setup an exception handler to unlock the root method synchronized object - syncHandler = new CiExceptionHandler(0, method.code().length, Instruction.SYNCHRONIZATION_ENTRY_BCI, 0, null); - } else { - // 4B.1 simply finish the start block - finishStartBlock(startBlock); - - if (createUnwind) { - syncHandler = new CiExceptionHandler(0, method.code().length, Instruction.SYNCHRONIZATION_ENTRY_BCI, 0, null); - } - } - - // 5. SKIPPED: look for intrinsics - - // 6B.1 do the normal parsing - addToWorkList(blockFromBci[0]); - iterateAllBlocks(); - - // remove Placeholders - for (Node n : graph.getNodes()) { - if (n instanceof Placeholder) { - Placeholder p = (Placeholder) n; - assert p.blockPredecessors().size() == 1; - Node pred = p.blockPredecessors().get(0); - int predIndex = p.predecessorsIndex().get(0); - pred.successors().setAndClear(predIndex, p, 0); - p.delete(); - } - } - - // remove FrameStates - for (Node n : graph.getNodes()) { - if (n instanceof FrameState) { - boolean delete = false; - if (n.usages().size() == 0 && n.predecessors().size() == 0) { - delete = true; - } - if (delete) { - n.delete(); - } - } - } - } - - private int nextBlockNumber() { - stats.blockCount++; - return nextBlockNumber++; - } - - private Block nextBlock(int bci) { - Block block = new Block(); - block.startBci = bci; - block.endBci = bci; - block.blockID = nextBlockNumber(); - return block; - } - - private Block unwindBlock() { - if (unwindBlock == null) { - unwindBlock = new Block(); - unwindBlock.startBci = Instruction.SYNCHRONIZATION_ENTRY_BCI; - unwindBlock.endBci = Instruction.SYNCHRONIZATION_ENTRY_BCI; - unwindBlock.blockID = nextBlockNumber(); - addToWorkList(unwindBlock); - } - return unwindBlock; - } - - private Block returnBlock() { - if (returnBlock == null) { - returnBlock = new Block(); - returnBlock.startBci = Instruction.SYNCHRONIZATION_ENTRY_BCI; - returnBlock.endBci = Instruction.SYNCHRONIZATION_ENTRY_BCI; - returnBlock.blockID = nextBlockNumber(); - addToWorkList(returnBlock); - } - return returnBlock; - } - - private void markOnWorkList(Block block) { - blocksOnWorklist.add(block); - } - - private boolean isOnWorkList(Block block) { - return blocksOnWorklist.contains(block); - } - - private void markVisited(Block block) { - blocksVisited.add(block); - } - - private boolean isVisited(Block block) { - return blocksVisited.contains(block); - } - - private void finishStartBlock(Block startBlock) { - assert bci() == 0; - Instruction target = createTargetAt(0, frameState); - appendGoto(target); - } - - public void mergeOrClone(Block target, FrameStateAccess newState) { - Instruction first = target.firstInstruction; - if (target.isLoopHeader && isVisited(target)) { - first = ((LoopBegin) first).loopEnd(); - } - assert first instanceof StateSplit; - - int bci = target.startBci; - - FrameState existingState = ((StateSplit) first).stateBefore(); - - if (existingState == null) { - // copy state because it is modified - FrameState duplicate = newState.duplicate(bci); - - // if the block is a loop header, insert all necessary phis - if (first instanceof LoopBegin && target.isLoopHeader) { - assert first instanceof Merge; - insertLoopPhis((Merge) first, duplicate); - ((Merge) first).setStateBefore(duplicate); - } else { - ((StateSplit) first).setStateBefore(duplicate); - } - } else { - if (!C1XOptions.AssumeVerifiedBytecode && !existingState.isCompatibleWith(newState)) { - // stacks or locks do not match--bytecodes would not verify - TTY.println(existingState.toString()); - TTY.println(newState.duplicate(0).toString()); - throw new CiBailout("stack or locks do not match"); - } - assert existingState.localsSize() == newState.localsSize(); - assert existingState.stackSize() == newState.stackSize(); - - if (first instanceof Placeholder) { - assert !target.isLoopHeader; - Merge merge = new Merge(graph); - - Placeholder p = (Placeholder) first; - assert p.next() == null; - p.replace(merge); - target.firstInstruction = merge; - merge.setStateBefore(existingState); - first = merge; - } - - existingState.merge((Merge) first, newState); - } - - for (int j = 0; j < frameState.localsSize() + frameState.stackSize(); ++j) { - if (frameState.valueAt(j) != null) { - assert !frameState.valueAt(j).isDeleted(); - } - } - } - - private void insertLoopPhis(Merge merge, FrameState newState) { - int stackSize = newState.stackSize(); - for (int i = 0; i < stackSize; i++) { - // always insert phis for the stack - Value x = newState.stackAt(i); - if (x != null) { - newState.setupPhiForStack(merge, i).addInput(x); - } - } - int localsSize = newState.localsSize(); - for (int i = 0; i < localsSize; i++) { - Value x = newState.localAt(i); - if (x != null) { - newState.setupPhiForLocal(merge, i).addInput(x); - } - } - } - - public BytecodeStream stream() { - return stream; - } - - public int bci() { - return stream.currentBCI(); - } - - private void loadLocal(int index, CiKind kind) { - frameState.push(kind, frameState.loadLocal(index)); - } - - private void storeLocal(CiKind kind, int index) { - frameState.storeLocal(index, frameState.pop(kind)); - } - - public boolean covers(RiExceptionHandler handler, int bci) { - return handler.startBCI() <= bci && bci < handler.endBCI(); - } - - public boolean isCatchAll(RiExceptionHandler handler) { - return handler.catchTypeCPI() == 0; - } - - private Instruction handleException(Value exceptionObject, int bci) { - assert bci == Instruction.SYNCHRONIZATION_ENTRY_BCI || bci == bci() : "invalid bci"; - - RiExceptionHandler firstHandler = null; - RiExceptionHandler[] exceptionHandlers = method.exceptionHandlers(); - // join with all potential exception handlers - if (exceptionHandlers != null) { - for (RiExceptionHandler handler : exceptionHandlers) { - // if the handler covers this bytecode index, add it to the list - if (covers(handler, bci)) { - firstHandler = handler; - break; - } - } - } - - if (firstHandler == null) { - firstHandler = syncHandler; - } - - if (firstHandler != null) { - compilation.setHasExceptionHandlers(); - - Block dispatchBlock = null; - for (Block block : blockList) { - if (block instanceof ExceptionBlock) { - ExceptionBlock excBlock = (ExceptionBlock) block; - if (excBlock.handler == firstHandler) { - dispatchBlock = block; - break; - } - } - } - // if there's no dispatch block then the catch block needs to be a catch all - if (dispatchBlock == null) { - assert isCatchAll(firstHandler); - int handlerBCI = firstHandler.handlerBCI(); - if (handlerBCI == Instruction.SYNCHRONIZATION_ENTRY_BCI) { - dispatchBlock = unwindBlock(); - } else { - dispatchBlock = blockFromBci[handlerBCI]; - } - } - FrameState entryState = frameState.duplicateWithEmptyStack(bci); - - StateSplit entry = new Placeholder(graph); - entry.setStateBefore(entryState); - - Instruction currentNext = entry; - Value currentExceptionObject = exceptionObject; - if (currentExceptionObject == null) { - ExceptionObject exception = new ExceptionObject(graph); - entry.setNext(exception); - currentNext = exception; - currentExceptionObject = exception; - } - FrameState stateWithException = entryState.duplicateModified(bci, CiKind.Void, currentExceptionObject); - - Instruction successor = createTarget(dispatchBlock, stateWithException); - currentNext.setNext(successor); - return entry; - } - return null; - } - - private void genLoadConstant(int cpi) { - Object con = constantPool.lookupConstant(cpi); - - if (con instanceof RiType) { - // this is a load of class constant which might be unresolved - RiType riType = (RiType) con; - if (!riType.isResolved()) { - append(new Deoptimize(graph)); - frameState.push(CiKind.Object, append(Constant.forObject(null, graph))); - } else { - frameState.push(CiKind.Object, append(new Constant(riType.getEncoding(Representation.JavaClass), graph))); - } - } else if (con instanceof CiConstant) { - CiConstant constant = (CiConstant) con; - frameState.push(constant.kind.stackKind(), appendConstant(constant)); - } else { - throw new Error("lookupConstant returned an object of incorrect type"); - } - } - - private void genLoadIndexed(CiKind kind) { - Value index = frameState.ipop(); - Value array = frameState.apop(); - Value length = append(new ArrayLength(array, graph)); - Value v = append(new LoadIndexed(array, index, length, kind, graph)); - frameState.push(kind.stackKind(), v); - } - - private void genStoreIndexed(CiKind kind) { - Value value = frameState.pop(kind.stackKind()); - Value index = frameState.ipop(); - Value array = frameState.apop(); - Value length = append(new ArrayLength(array, graph)); - StoreIndexed result = new StoreIndexed(array, index, length, kind, value, graph); - append(result); - } - - private void stackOp(int opcode) { - switch (opcode) { - case POP: { - frameState.xpop(); - break; - } - case POP2: { - frameState.xpop(); - frameState.xpop(); - break; - } - case DUP: { - Value w = frameState.xpop(); - frameState.xpush(w); - frameState.xpush(w); - break; - } - case DUP_X1: { - Value w1 = frameState.xpop(); - Value w2 = frameState.xpop(); - frameState.xpush(w1); - frameState.xpush(w2); - frameState.xpush(w1); - break; - } - case DUP_X2: { - Value w1 = frameState.xpop(); - Value w2 = frameState.xpop(); - Value w3 = frameState.xpop(); - frameState.xpush(w1); - frameState.xpush(w3); - frameState.xpush(w2); - frameState.xpush(w1); - break; - } - case DUP2: { - Value w1 = frameState.xpop(); - Value w2 = frameState.xpop(); - frameState.xpush(w2); - frameState.xpush(w1); - frameState.xpush(w2); - frameState.xpush(w1); - break; - } - case DUP2_X1: { - Value w1 = frameState.xpop(); - Value w2 = frameState.xpop(); - Value w3 = frameState.xpop(); - frameState.xpush(w2); - frameState.xpush(w1); - frameState.xpush(w3); - frameState.xpush(w2); - frameState.xpush(w1); - break; - } - case DUP2_X2: { - Value w1 = frameState.xpop(); - Value w2 = frameState.xpop(); - Value w3 = frameState.xpop(); - Value w4 = frameState.xpop(); - frameState.xpush(w2); - frameState.xpush(w1); - frameState.xpush(w4); - frameState.xpush(w3); - frameState.xpush(w2); - frameState.xpush(w1); - break; - } - case SWAP: { - Value w1 = frameState.xpop(); - Value w2 = frameState.xpop(); - frameState.xpush(w1); - frameState.xpush(w2); - break; - } - default: - throw Util.shouldNotReachHere(); - } - - } - - private void genArithmeticOp(CiKind kind, int opcode) { - genArithmeticOp(kind, opcode, false); - } - - private void genArithmeticOp(CiKind kind, int opcode, boolean canTrap) { - genArithmeticOp(kind, opcode, kind, kind, canTrap); - } - - private void genArithmeticOp(CiKind result, int opcode, CiKind x, CiKind y, boolean canTrap) { - Value yValue = frameState.pop(y); - Value xValue = frameState.pop(x); - Value result1 = append(new Arithmetic(opcode, result, xValue, yValue, isStrict(method.accessFlags()), canTrap, graph)); - if (canTrap) { - append(new ValueAnchor(result1, graph)); - } - frameState.push(result, result1); - } - - private void genNegateOp(CiKind kind) { - frameState.push(kind, append(new Negate(frameState.pop(kind), graph))); - } - - private void genShiftOp(CiKind kind, int opcode) { - Value s = frameState.ipop(); - Value x = frameState.pop(kind); - Shift v; - switch(opcode){ - case ISHL: - case LSHL: v = new LeftShift(kind, x, s, graph); break; - case ISHR: - case LSHR: v = new RightShift(kind, x, s, graph); break; - case IUSHR: - case LUSHR: v = new UnsignedRightShift(kind, x, s, graph); break; - default: - throw new CiBailout("should not reach"); - } - frameState.push(kind, append(v)); - } - - private void genLogicOp(CiKind kind, int opcode) { - Value y = frameState.pop(kind); - Value x = frameState.pop(kind); - Logic v; - switch(opcode){ - case IAND: - case LAND: v = new And(kind, x, y, graph); break; - case IOR: - case LOR: v = new Or(kind, x, y, graph); break; - case IXOR: - case LXOR: v = new Xor(kind, x, y, graph); break; - default: - throw new CiBailout("should not reach"); - } - frameState.push(kind, append(v)); - } - - private void genCompareOp(CiKind kind, int opcode, CiKind resultKind) { - Value y = frameState.pop(kind); - Value x = frameState.pop(kind); - Value value = append(new NormalizeCompare(opcode, resultKind, x, y, graph)); - if (!resultKind.isVoid()) { - frameState.ipush(value); - } - } - - private void genConvert(int opcode, CiKind from, CiKind to) { - CiKind tt = to.stackKind(); - frameState.push(tt, append(new Convert(opcode, frameState.pop(from.stackKind()), tt, graph))); - } - - private void genIncrement() { - int index = stream().readLocalIndex(); - int delta = stream().readIncrement(); - Value x = frameState.localAt(index); - Value y = append(Constant.forInt(delta, graph)); - frameState.storeLocal(index, append(new Arithmetic(IADD, CiKind.Int, x, y, isStrict(method.accessFlags()), false, graph))); - } - - private void genGoto(int fromBCI, int toBCI) { - appendGoto(createTargetAt(toBCI, frameState)); - } - - private void ifNode(Value x, Condition cond, Value y) { - assert !x.isDeleted() && !y.isDeleted(); - If ifNode = new If(new Compare(x, cond, y, graph), graph); - append(ifNode); - Instruction tsucc = createTargetAt(stream().readBranchDest(), frameState); - ifNode.setBlockSuccessor(0, tsucc); - Instruction fsucc = createTargetAt(stream().nextBCI(), frameState); - ifNode.setBlockSuccessor(1, fsucc); - } - - private void genIfZero(Condition cond) { - Value y = appendConstant(CiConstant.INT_0); - Value x = frameState.ipop(); - ifNode(x, cond, y); - } - - private void genIfNull(Condition cond) { - Value y = appendConstant(CiConstant.NULL_OBJECT); - Value x = frameState.apop(); - ifNode(x, cond, y); - } - - private void genIfSame(CiKind kind, Condition cond) { - Value y = frameState.pop(kind); - Value x = frameState.pop(kind); - assert !x.isDeleted() && !y.isDeleted(); - ifNode(x, cond, y); - } - - private void genThrow(int bci) { - Value exception = frameState.apop(); - append(new NullCheck(exception, graph)); - - Instruction entry = handleException(exception, bci); - if (entry != null) { - append(entry); - } else { - frameState.clearStack(); - frameState.apush(exception); - appendGoto(createTarget(unwindBlock(), frameState)); - } - } - - private void genCheckCast() { - int cpi = stream().readCPI(); - RiType type = constantPool.lookupType(cpi, CHECKCAST); - boolean isInitialized = type.isResolved(); - Value typeInstruction = genTypeOrDeopt(RiType.Representation.ObjectHub, type, isInitialized, cpi); - Value object = frameState.apop(); - if (typeInstruction != null) { - frameState.apush(append(new CheckCast(type, typeInstruction, object, graph))); - } else { - frameState.apush(appendConstant(CiConstant.NULL_OBJECT)); - } - } - - private void genInstanceOf() { - int cpi = stream().readCPI(); - RiType type = constantPool.lookupType(cpi, INSTANCEOF); - boolean isInitialized = type.isResolved(); - Value typeInstruction = genTypeOrDeopt(RiType.Representation.ObjectHub, type, isInitialized, cpi); - Value object = frameState.apop(); - if (typeInstruction != null) { - frameState.ipush(append(new InstanceOf(type, typeInstruction, object, graph))); - } else { - frameState.ipush(appendConstant(CiConstant.INT_0)); - } - } - - void genNewInstance(int cpi) { - RiType type = constantPool.lookupType(cpi, NEW); - if (type.isResolved()) { - NewInstance n = new NewInstance(type, cpi, constantPool, graph); - frameState.apush(append(n)); - } else { - append(new Deoptimize(graph)); - frameState.apush(appendConstant(CiConstant.NULL_OBJECT)); - } - } - - private void genNewTypeArray(int typeCode) { - CiKind kind = CiKind.fromArrayTypeCode(typeCode); - RiType elementType = runtime.asRiType(kind); - NewTypeArray nta = new NewTypeArray(frameState.ipop(), elementType, graph); - frameState.apush(append(nta)); - } - - private void genNewObjectArray(int cpi) { - RiType type = constantPool.lookupType(cpi, ANEWARRAY); - Value length = frameState.ipop(); - if (type.isResolved()) { - NewArray n = new NewObjectArray(type, length, graph); - frameState.apush(append(n)); - } else { - append(new Deoptimize(graph)); - frameState.apush(appendConstant(CiConstant.NULL_OBJECT)); - } - - } - - private void genNewMultiArray(int cpi) { - RiType type = constantPool.lookupType(cpi, MULTIANEWARRAY); - int rank = stream().readUByte(bci() + 3); - Value[] dims = new Value[rank]; - for (int i = rank - 1; i >= 0; i--) { - dims[i] = frameState.ipop(); - } - if (type.isResolved()) { - NewArray n = new NewMultiArray(type, dims, cpi, constantPool, graph); - frameState.apush(append(n)); - } else { - append(new Deoptimize(graph)); - frameState.apush(appendConstant(CiConstant.NULL_OBJECT)); - } - } - - private void genGetField(int cpi, RiField field) { - CiKind kind = field.kind(); - Value receiver = frameState.apop(); - if (field.isResolved()) { - LoadField load = new LoadField(receiver, field, graph); - appendOptimizedLoadField(kind, load); - } else { - append(new Deoptimize(graph)); - frameState.push(kind.stackKind(), append(Constant.defaultForKind(kind, graph))); - } - } - - private void genPutField(int cpi, RiField field) { - Value value = frameState.pop(field.kind().stackKind()); - Value receiver = frameState.apop(); - if (field.isResolved()) { - StoreField store = new StoreField(receiver, field, value, graph); - appendOptimizedStoreField(store); - } else { - append(new Deoptimize(graph)); - } - } - - private void genGetStatic(int cpi, RiField field) { - RiType holder = field.holder(); - boolean isInitialized = field.isResolved(); - CiConstant constantValue = null; - if (isInitialized) { - constantValue = field.constantValue(null); - } - if (constantValue != null) { - frameState.push(constantValue.kind.stackKind(), appendConstant(constantValue)); - } else { - Value container = genTypeOrDeopt(RiType.Representation.StaticFields, holder, isInitialized, cpi); - CiKind kind = field.kind(); - if (container != null) { - LoadField load = new LoadField(container, field, graph); - appendOptimizedLoadField(kind, load); - } else { - append(new Deoptimize(graph)); - frameState.push(kind.stackKind(), append(Constant.defaultForKind(kind, graph))); - } - } - } - - private void genPutStatic(int cpi, RiField field) { - RiType holder = field.holder(); - Value container = genTypeOrDeopt(RiType.Representation.StaticFields, holder, field.isResolved(), cpi); - Value value = frameState.pop(field.kind().stackKind()); - if (container != null) { - StoreField store = new StoreField(container, field, value, graph); - appendOptimizedStoreField(store); - } else { - append(new Deoptimize(graph)); - } - } - - private Value genTypeOrDeopt(RiType.Representation representation, RiType holder, boolean initialized, int cpi) { - if (initialized) { - return appendConstant(holder.getEncoding(representation)); - } else { - append(new Deoptimize(graph)); - return null; - } - } - - private void appendOptimizedStoreField(StoreField store) { - append(store); - } - - private void appendOptimizedLoadField(CiKind kind, LoadField load) { - // append the load to the instruction - Value optimized = append(load); - frameState.push(kind.stackKind(), optimized); - } - - private void genInvokeStatic(RiMethod target, int cpi, RiConstantPool constantPool) { - RiType holder = target.holder(); - boolean isInitialized = target.isResolved() && holder.isInitialized(); - if (!isInitialized && C1XOptions.ResolveClassBeforeStaticInvoke) { - // Re-use the same resolution code as for accessing a static field. Even though - // the result of resolution is not used by the invocation (only the side effect - // of initialization is required), it can be commoned with static field accesses. - genTypeOrDeopt(RiType.Representation.StaticFields, holder, isInitialized, cpi); - } - Value[] args = frameState.popArguments(target.signature().argumentSlots(false)); - appendInvoke(INVOKESTATIC, target, args, cpi, constantPool); - } - - private void genInvokeInterface(RiMethod target, int cpi, RiConstantPool constantPool) { - Value[] args = frameState.popArguments(target.signature().argumentSlots(true)); - genInvokeIndirect(INVOKEINTERFACE, target, args, cpi, constantPool); - - } - - private void genInvokeVirtual(RiMethod target, int cpi, RiConstantPool constantPool) { - Value[] args = frameState.popArguments(target.signature().argumentSlots(true)); - genInvokeIndirect(INVOKEVIRTUAL, target, args, cpi, constantPool); - - } - - private void genInvokeSpecial(RiMethod target, RiType knownHolder, int cpi, RiConstantPool constantPool) { - Value[] args = frameState.popArguments(target.signature().argumentSlots(true)); - invokeDirect(target, args, knownHolder, cpi, constantPool); - - } - - private void genInvokeIndirect(int opcode, RiMethod target, Value[] args, int cpi, RiConstantPool constantPool) { - Value receiver = args[0]; - // attempt to devirtualize the call - if (target.isResolved()) { - RiType klass = target.holder(); - - // 0. check for trivial cases - if (target.canBeStaticallyBound() && !isAbstract(target.accessFlags())) { - // check for trivial cases (e.g. final methods, nonvirtual methods) - invokeDirect(target, args, target.holder(), cpi, constantPool); - return; - } - // 1. check if the exact type of the receiver can be determined - RiType exact = getExactType(klass, receiver); - if (exact != null && exact.isResolved()) { - // either the holder class is exact, or the receiver object has an exact type - invokeDirect(exact.resolveMethodImpl(target), args, exact, cpi, constantPool); - return; - } - } - // devirtualization failed, produce an actual invokevirtual - appendInvoke(opcode, target, args, cpi, constantPool); - } - - private CiKind returnKind(RiMethod target) { - return target.signature().returnKind(); - } - - private void invokeDirect(RiMethod target, Value[] args, RiType knownHolder, int cpi, RiConstantPool constantPool) { - appendInvoke(INVOKESPECIAL, target, args, cpi, constantPool); - } - - private void appendInvoke(int opcode, RiMethod target, Value[] args, int cpi, RiConstantPool constantPool) { - CiKind resultType = returnKind(target); - Invoke invoke = new Invoke(bci(), opcode, resultType.stackKind(), args, target, target.signature().returnType(method.holder()), graph); - Value result = appendWithBCI(invoke); - invoke.setExceptionEdge(handleException(null, bci())); - frameState.pushReturn(resultType, result); - } - - private RiType getExactType(RiType staticType, Value receiver) { - RiType exact = staticType.exactType(); - if (exact == null) { - exact = receiver.exactType(); - if (exact == null) { - if (receiver.isConstant()) { - exact = runtime.getTypeOf(receiver.asConstant()); - } - if (exact == null) { - RiType declared = receiver.declaredType(); - exact = declared == null || !declared.isResolved() ? null : declared.exactType(); - } - } - } - return exact; - } - - private void callRegisterFinalizer() { - Value receiver = frameState.loadLocal(0); - RiType declaredType = receiver.declaredType(); - RiType receiverType = declaredType; - RiType exactType = receiver.exactType(); - if (exactType == null && declaredType != null) { - exactType = declaredType.exactType(); - } - if (exactType == null && receiver instanceof Local && ((Local) receiver).index() == 0) { - // the exact type isn't known, but the receiver is parameter 0 => use holder - receiverType = method.holder(); - exactType = receiverType.exactType(); - } - boolean needsCheck = true; - if (exactType != null) { - // we have an exact type - needsCheck = exactType.hasFinalizer(); - } else { - // if either the declared type of receiver or the holder can be assumed to have no finalizers - if (declaredType != null && !declaredType.hasFinalizableSubclass()) { - if (compilation.recordNoFinalizableSubclassAssumption(declaredType)) { - needsCheck = false; - } - } - - if (receiverType != null && !receiverType.hasFinalizableSubclass()) { - if (compilation.recordNoFinalizableSubclassAssumption(receiverType)) { - needsCheck = false; - } - } - } - - if (needsCheck) { - // append a call to the finalizer registration - append(new RegisterFinalizer(frameState.loadLocal(0), frameState.create(bci()), graph)); - C1XMetrics.InlinedFinalizerChecks++; - } - } - - private void genReturn(Value x) { - frameState.clearStack(); - if (x != null) { - frameState.push(x.kind, x); - } - appendGoto(createTarget(returnBlock(), frameState)); - } - - private void genMonitorEnter(Value x, int bci) { - int lockNumber = frameState.locksSize(); - MonitorAddress lockAddress = null; - if (runtime.sizeOfBasicObjectLock() != 0) { - lockAddress = new MonitorAddress(lockNumber, graph); - append(lockAddress); - } - MonitorEnter monitorEnter = new MonitorEnter(x, lockAddress, lockNumber, graph); - appendWithBCI(monitorEnter); - frameState.lock(x); - if (bci == Instruction.SYNCHRONIZATION_ENTRY_BCI) { - monitorEnter.setStateAfter(frameState.create(0)); - } - } - - private void genMonitorExit(Value x) { - int lockNumber = frameState.locksSize() - 1; - if (lockNumber < 0) { - throw new CiBailout("monitor stack underflow"); - } - MonitorAddress lockAddress = null; - if (runtime.sizeOfBasicObjectLock() != 0) { - lockAddress = new MonitorAddress(lockNumber, graph); - append(lockAddress); - } - appendWithBCI(new MonitorExit(x, lockAddress, lockNumber, graph)); - frameState.unlock(); - } - - private void genJsr(int dest) { - throw new CiBailout("jsr/ret not supported"); - } - - private void genRet(int localIndex) { - throw new CiBailout("jsr/ret not supported"); - } - - private void genTableswitch() { - int bci = bci(); - Value value = frameState.ipop(); - BytecodeTableSwitch ts = new BytecodeTableSwitch(stream(), bci); - int max = ts.numberOfCases(); - List list = new ArrayList(max + 1); - List offsetList = new ArrayList(max + 1); - for (int i = 0; i < max; i++) { - // add all successors to the successor list - int offset = ts.offsetAt(i); - list.add(null); - offsetList.add(offset); - } - int offset = ts.defaultOffset(); - list.add(null); - offsetList.add(offset); - TableSwitch tableSwitch = new TableSwitch(value, list, ts.lowKey(), graph); - for (int i = 0; i < offsetList.size(); ++i) { - tableSwitch.setBlockSuccessor(i, createTargetAt(bci + offsetList.get(i), frameState)); - } - append(tableSwitch); - } - - private void genLookupswitch() { - int bci = bci(); - Value value = frameState.ipop(); - BytecodeLookupSwitch ls = new BytecodeLookupSwitch(stream(), bci); - int max = ls.numberOfCases(); - List list = new ArrayList(max + 1); - List offsetList = new ArrayList(max + 1); - int[] keys = new int[max]; - for (int i = 0; i < max; i++) { - // add all successors to the successor list - int offset = ls.offsetAt(i); - list.add(null); - offsetList.add(offset); - keys[i] = ls.keyAt(i); - } - int offset = ls.defaultOffset(); - list.add(null); - offsetList.add(offset); - LookupSwitch lookupSwitch = new LookupSwitch(value, list, keys, graph); - for (int i = 0; i < offsetList.size(); ++i) { - lookupSwitch.setBlockSuccessor(i, createTargetAt(bci + offsetList.get(i), frameState)); - } - append(lookupSwitch); - } - - private Value appendConstant(CiConstant constant) { - return append(new Constant(constant, graph)); - } - - private Value append(Instruction x) { - return appendWithBCI(x); - } - - private Value append(Value v) { - return v; - } - - private Value appendWithBCI(Instruction x) { - assert x.predecessors().size() == 0 : "instruction should not have been appended yet"; - assert lastInstr.next() == null : "cannot append instruction to instruction which isn't end (" + lastInstr + "->" + lastInstr.next() + ")"; - lastInstr.setNext(x); - - lastInstr = x; - if (++stats.nodeCount >= C1XOptions.MaximumInstructionCount) { - // bailout if we've exceeded the maximum inlining size - throw new CiBailout("Method and/or inlining is too large"); - } - - return x; - } - - private Instruction createTargetAt(int bci, FrameStateAccess stateAfter) { - return createTarget(blockFromBci[bci], stateAfter); - } - - private Instruction createTarget(Block block, FrameStateAccess stateAfter) { - assert block != null && stateAfter != null; - assert block.isLoopHeader || block.firstInstruction == null || block.firstInstruction.next() == null : "non-loop block must be iterated after all its predecessors"; - - if (block.isExceptionEntry) { - assert stateAfter.stackSize() == 1; - } - - if (block.firstInstruction == null) { - if (block.isLoopHeader) { -// block.firstInstruction = new Merge(block.startBci, graph); - - LoopBegin loopBegin = new LoopBegin(graph); - LoopEnd loopEnd = new LoopEnd(graph); - loopEnd.setLoopBegin(loopBegin); - block.firstInstruction = loopBegin; - } else { - block.firstInstruction = new Placeholder(graph); - } - } - mergeOrClone(block, stateAfter); - addToWorkList(block); - - if (block.firstInstruction instanceof LoopBegin && isVisited(block)) { - return ((LoopBegin) block.firstInstruction).loopEnd(); - } else { - return block.firstInstruction; - } - } - - private Value synchronizedObject(FrameStateAccess state, RiMethod target) { - if (isStatic(target.accessFlags())) { - Constant classConstant = new Constant(target.holder().getEncoding(Representation.JavaClass), graph); - return append(classConstant); - } else { - return state.localAt(0); - } - } - - private void iterateAllBlocks() { - Block block; - while ((block = removeFromWorkList()) != null) { - - // remove blocks that have no predecessors by the time it their bytecodes are parsed - if (block.firstInstruction == null) { - markVisited(block); - continue; - } - - if (!isVisited(block)) { - markVisited(block); - // now parse the block - frameState.initializeFrom(((StateSplit) block.firstInstruction).stateBefore()); - lastInstr = block.firstInstruction; - assert block.firstInstruction.next() == null : "instructions already appended at block " + block.blockID; - - if (block == returnBlock) { - createReturnBlock(block); - } else if (block == unwindBlock) { - createUnwindBlock(block); - } else if (block instanceof ExceptionBlock) { - createExceptionDispatch((ExceptionBlock) block); - } else { - iterateBytecodesForBlock(block); - } - } - } - for (Block b : blocksVisited) { - if (b.isLoopHeader) { - LoopBegin begin = (LoopBegin) b.firstInstruction; - LoopEnd end = begin.loopEnd(); - -// This can happen with degenerated loops like this one: -// for (;;) { -// try { -// break; -// } catch (UnresolvedException iioe) { -// } -// } - if (end.stateBefore() != null) { - begin.stateBefore().merge(begin, end.stateBefore()); - } else { - end.delete(); - Merge merge = new Merge(graph); - merge.successors().setAndClear(merge.nextIndex(), begin, begin.nextIndex()); - begin.replace(merge); - } - } - } - } - - private void createUnwindBlock(Block block) { - if (Modifier.isSynchronized(method.accessFlags())) { - genMonitorExit(methodSynchronizedObject); - } - append(graph.createUnwind(frameState.apop())); - } - - private void createReturnBlock(Block block) { - if (method.isConstructor() && method.holder().superType() == null) { - callRegisterFinalizer(); - } - CiKind returnKind = method.signature().returnKind().stackKind(); - Value x = returnKind == CiKind.Void ? null : frameState.pop(returnKind); - assert frameState.stackSize() == 0; - - if (Modifier.isSynchronized(method.accessFlags())) { - genMonitorExit(methodSynchronizedObject); - } - append(graph.createReturn(x)); - } - - private void createExceptionDispatch(ExceptionBlock block) { - if (block.handler == null) { - assert frameState.stackSize() == 1 : "only exception object expected on stack, actual size: " + frameState.stackSize(); - createUnwindBlock(block); - } else { - assert frameState.stackSize() == 1; - - Block nextBlock = block.next == null ? unwindBlock() : block.next; - if (block.handler.catchType().isResolved()) { - Instruction catchSuccessor = createTarget(blockFromBci[block.handler.handlerBCI()], frameState); - Instruction nextDispatch = createTarget(nextBlock, frameState); - append(new ExceptionDispatch(frameState.stackAt(0), catchSuccessor, nextDispatch, block.handler.catchType(), graph)); - } else { - Deoptimize deopt = new Deoptimize(graph); - deopt.setMessage("unresolved " + block.handler.catchType().name()); - append(deopt); - Instruction nextDispatch = createTarget(nextBlock, frameState); - appendGoto(nextDispatch); - } - } - } - - private void appendGoto(Instruction target) { - lastInstr.setNext(target); - } - - private void iterateBytecodesForBlock(Block block) { - assert frameState != null; - - stream.setBCI(block.startBci); - - int endBCI = stream.endBCI(); - boolean blockStart = true; - - int bci = block.startBci; - while (bci < endBCI) { - Block nextBlock = blockFromBci[bci]; - if (nextBlock != null && nextBlock != block) { - assert !nextBlock.isExceptionEntry; - // we fell through to the next block, add a goto and break - appendGoto(createTarget(nextBlock, frameState)); - break; - } - // read the opcode - int opcode = stream.currentBC(); - - traceState(); - traceInstruction(bci, opcode, blockStart); - processBytecode(bci, opcode); - - if (Schedule.isBlockEnd(lastInstr) || lastInstr.next() != null) { - break; - } - - stream.next(); - bci = stream.currentBCI(); - if (lastInstr instanceof StateSplit) { - StateSplit stateSplit = (StateSplit) lastInstr; - if (stateSplit.stateAfter() == null && stateSplit.needsStateAfter()) { - stateSplit.setStateAfter(frameState.create(bci)); - } - } - blockStart = false; - } - } - - private void traceState() { - if (C1XOptions.TraceBytecodeParserLevel >= TRACELEVEL_STATE && !TTY.isSuppressed()) { - log.println(String.format("| state [nr locals = %d, stack depth = %d, method = %s]", frameState.localsSize(), frameState.stackSize(), method)); - for (int i = 0; i < frameState.localsSize(); ++i) { - Value value = frameState.localAt(i); - log.println(String.format("| local[%d] = %-8s : %s", i, value == null ? "bogus" : value.kind.javaName, value)); - } - for (int i = 0; i < frameState.stackSize(); ++i) { - Value value = frameState.stackAt(i); - log.println(String.format("| stack[%d] = %-8s : %s", i, value == null ? "bogus" : value.kind.javaName, value)); - } - for (int i = 0; i < frameState.locksSize(); ++i) { - Value value = frameState.lockAt(i); - log.println(String.format("| lock[%d] = %-8s : %s", i, value == null ? "bogus" : value.kind.javaName, value)); - } - } - } - - private void processBytecode(int bci, int opcode) { - int cpi; - - // Checkstyle: stop - switch (opcode) { - case NOP : /* nothing to do */ break; - case ACONST_NULL : frameState.apush(appendConstant(CiConstant.NULL_OBJECT)); break; - case ICONST_M1 : frameState.ipush(appendConstant(CiConstant.INT_MINUS_1)); break; - case ICONST_0 : frameState.ipush(appendConstant(CiConstant.INT_0)); break; - case ICONST_1 : frameState.ipush(appendConstant(CiConstant.INT_1)); break; - case ICONST_2 : frameState.ipush(appendConstant(CiConstant.INT_2)); break; - case ICONST_3 : frameState.ipush(appendConstant(CiConstant.INT_3)); break; - case ICONST_4 : frameState.ipush(appendConstant(CiConstant.INT_4)); break; - case ICONST_5 : frameState.ipush(appendConstant(CiConstant.INT_5)); break; - case LCONST_0 : frameState.lpush(appendConstant(CiConstant.LONG_0)); break; - case LCONST_1 : frameState.lpush(appendConstant(CiConstant.LONG_1)); break; - case FCONST_0 : frameState.fpush(appendConstant(CiConstant.FLOAT_0)); break; - case FCONST_1 : frameState.fpush(appendConstant(CiConstant.FLOAT_1)); break; - case FCONST_2 : frameState.fpush(appendConstant(CiConstant.FLOAT_2)); break; - case DCONST_0 : frameState.dpush(appendConstant(CiConstant.DOUBLE_0)); break; - case DCONST_1 : frameState.dpush(appendConstant(CiConstant.DOUBLE_1)); break; - case BIPUSH : frameState.ipush(appendConstant(CiConstant.forInt(stream.readByte()))); break; - case SIPUSH : frameState.ipush(appendConstant(CiConstant.forInt(stream.readShort()))); break; - case LDC : // fall through - case LDC_W : // fall through - case LDC2_W : genLoadConstant(stream.readCPI()); break; - case ILOAD : loadLocal(stream.readLocalIndex(), CiKind.Int); break; - case LLOAD : loadLocal(stream.readLocalIndex(), CiKind.Long); break; - case FLOAD : loadLocal(stream.readLocalIndex(), CiKind.Float); break; - case DLOAD : loadLocal(stream.readLocalIndex(), CiKind.Double); break; - case ALOAD : loadLocal(stream.readLocalIndex(), CiKind.Object); break; - case ILOAD_0 : // fall through - case ILOAD_1 : // fall through - case ILOAD_2 : // fall through - case ILOAD_3 : loadLocal(opcode - ILOAD_0, CiKind.Int); break; - case LLOAD_0 : // fall through - case LLOAD_1 : // fall through - case LLOAD_2 : // fall through - case LLOAD_3 : loadLocal(opcode - LLOAD_0, CiKind.Long); break; - case FLOAD_0 : // fall through - case FLOAD_1 : // fall through - case FLOAD_2 : // fall through - case FLOAD_3 : loadLocal(opcode - FLOAD_0, CiKind.Float); break; - case DLOAD_0 : // fall through - case DLOAD_1 : // fall through - case DLOAD_2 : // fall through - case DLOAD_3 : loadLocal(opcode - DLOAD_0, CiKind.Double); break; - case ALOAD_0 : // fall through - case ALOAD_1 : // fall through - case ALOAD_2 : // fall through - case ALOAD_3 : loadLocal(opcode - ALOAD_0, CiKind.Object); break; - case IALOAD : genLoadIndexed(CiKind.Int ); break; - case LALOAD : genLoadIndexed(CiKind.Long ); break; - case FALOAD : genLoadIndexed(CiKind.Float ); break; - case DALOAD : genLoadIndexed(CiKind.Double); break; - case AALOAD : genLoadIndexed(CiKind.Object); break; - case BALOAD : genLoadIndexed(CiKind.Byte ); break; - case CALOAD : genLoadIndexed(CiKind.Char ); break; - case SALOAD : genLoadIndexed(CiKind.Short ); break; - case ISTORE : storeLocal(CiKind.Int, stream.readLocalIndex()); break; - case LSTORE : storeLocal(CiKind.Long, stream.readLocalIndex()); break; - case FSTORE : storeLocal(CiKind.Float, stream.readLocalIndex()); break; - case DSTORE : storeLocal(CiKind.Double, stream.readLocalIndex()); break; - case ASTORE : storeLocal(CiKind.Object, stream.readLocalIndex()); break; - case ISTORE_0 : // fall through - case ISTORE_1 : // fall through - case ISTORE_2 : // fall through - case ISTORE_3 : storeLocal(CiKind.Int, opcode - ISTORE_0); break; - case LSTORE_0 : // fall through - case LSTORE_1 : // fall through - case LSTORE_2 : // fall through - case LSTORE_3 : storeLocal(CiKind.Long, opcode - LSTORE_0); break; - case FSTORE_0 : // fall through - case FSTORE_1 : // fall through - case FSTORE_2 : // fall through - case FSTORE_3 : storeLocal(CiKind.Float, opcode - FSTORE_0); break; - case DSTORE_0 : // fall through - case DSTORE_1 : // fall through - case DSTORE_2 : // fall through - case DSTORE_3 : storeLocal(CiKind.Double, opcode - DSTORE_0); break; - case ASTORE_0 : // fall through - case ASTORE_1 : // fall through - case ASTORE_2 : // fall through - case ASTORE_3 : storeLocal(CiKind.Object, opcode - ASTORE_0); break; - case IASTORE : genStoreIndexed(CiKind.Int ); break; - case LASTORE : genStoreIndexed(CiKind.Long ); break; - case FASTORE : genStoreIndexed(CiKind.Float ); break; - case DASTORE : genStoreIndexed(CiKind.Double); break; - case AASTORE : genStoreIndexed(CiKind.Object); break; - case BASTORE : genStoreIndexed(CiKind.Byte ); break; - case CASTORE : genStoreIndexed(CiKind.Char ); break; - case SASTORE : genStoreIndexed(CiKind.Short ); break; - case POP : // fall through - case POP2 : // fall through - case DUP : // fall through - case DUP_X1 : // fall through - case DUP_X2 : // fall through - case DUP2 : // fall through - case DUP2_X1 : // fall through - case DUP2_X2 : // fall through - case SWAP : stackOp(opcode); break; - case IADD : // fall through - case ISUB : // fall through - case IMUL : genArithmeticOp(CiKind.Int, opcode); break; - case IDIV : // fall through - case IREM : genArithmeticOp(CiKind.Int, opcode, true); break; - case LADD : // fall through - case LSUB : // fall through - case LMUL : genArithmeticOp(CiKind.Long, opcode); break; - case LDIV : // fall through - case LREM : genArithmeticOp(CiKind.Long, opcode, true); break; - case FADD : // fall through - case FSUB : // fall through - case FMUL : // fall through - case FDIV : // fall through - case FREM : genArithmeticOp(CiKind.Float, opcode); break; - case DADD : // fall through - case DSUB : // fall through - case DMUL : // fall through - case DDIV : // fall through - case DREM : genArithmeticOp(CiKind.Double, opcode); break; - case INEG : genNegateOp(CiKind.Int); break; - case LNEG : genNegateOp(CiKind.Long); break; - case FNEG : genNegateOp(CiKind.Float); break; - case DNEG : genNegateOp(CiKind.Double); break; - case ISHL : // fall through - case ISHR : // fall through - case IUSHR : genShiftOp(CiKind.Int, opcode); break; - case IAND : // fall through - case IOR : // fall through - case IXOR : genLogicOp(CiKind.Int, opcode); break; - case LSHL : // fall through - case LSHR : // fall through - case LUSHR : genShiftOp(CiKind.Long, opcode); break; - case LAND : // fall through - case LOR : // fall through - case LXOR : genLogicOp(CiKind.Long, opcode); break; - case IINC : genIncrement(); break; - case I2L : genConvert(opcode, CiKind.Int , CiKind.Long ); break; - case I2F : genConvert(opcode, CiKind.Int , CiKind.Float ); break; - case I2D : genConvert(opcode, CiKind.Int , CiKind.Double); break; - case L2I : genConvert(opcode, CiKind.Long , CiKind.Int ); break; - case L2F : genConvert(opcode, CiKind.Long , CiKind.Float ); break; - case L2D : genConvert(opcode, CiKind.Long , CiKind.Double); break; - case F2I : genConvert(opcode, CiKind.Float , CiKind.Int ); break; - case F2L : genConvert(opcode, CiKind.Float , CiKind.Long ); break; - case F2D : genConvert(opcode, CiKind.Float , CiKind.Double); break; - case D2I : genConvert(opcode, CiKind.Double, CiKind.Int ); break; - case D2L : genConvert(opcode, CiKind.Double, CiKind.Long ); break; - case D2F : genConvert(opcode, CiKind.Double, CiKind.Float ); break; - case I2B : genConvert(opcode, CiKind.Int , CiKind.Byte ); break; - case I2C : genConvert(opcode, CiKind.Int , CiKind.Char ); break; - case I2S : genConvert(opcode, CiKind.Int , CiKind.Short ); break; - case LCMP : genCompareOp(CiKind.Long, opcode, CiKind.Int); break; - case FCMPL : genCompareOp(CiKind.Float, opcode, CiKind.Int); break; - case FCMPG : genCompareOp(CiKind.Float, opcode, CiKind.Int); break; - case DCMPL : genCompareOp(CiKind.Double, opcode, CiKind.Int); break; - case DCMPG : genCompareOp(CiKind.Double, opcode, CiKind.Int); break; - case IFEQ : genIfZero(Condition.EQ); break; - case IFNE : genIfZero(Condition.NE); break; - case IFLT : genIfZero(Condition.LT); break; - case IFGE : genIfZero(Condition.GE); break; - case IFGT : genIfZero(Condition.GT); break; - case IFLE : genIfZero(Condition.LE); break; - case IF_ICMPEQ : genIfSame(CiKind.Int, Condition.EQ); break; - case IF_ICMPNE : genIfSame(CiKind.Int, Condition.NE); break; - case IF_ICMPLT : genIfSame(CiKind.Int, Condition.LT); break; - case IF_ICMPGE : genIfSame(CiKind.Int, Condition.GE); break; - case IF_ICMPGT : genIfSame(CiKind.Int, Condition.GT); break; - case IF_ICMPLE : genIfSame(CiKind.Int, Condition.LE); break; - case IF_ACMPEQ : genIfSame(frameState.peekKind(), Condition.EQ); break; - case IF_ACMPNE : genIfSame(frameState.peekKind(), Condition.NE); break; - case GOTO : genGoto(stream.currentBCI(), stream.readBranchDest()); break; - case JSR : genJsr(stream.readBranchDest()); break; - case RET : genRet(stream.readLocalIndex()); break; - case TABLESWITCH : genTableswitch(); break; - case LOOKUPSWITCH : genLookupswitch(); break; - case IRETURN : genReturn(frameState.ipop()); break; - case LRETURN : genReturn(frameState.lpop()); break; - case FRETURN : genReturn(frameState.fpop()); break; - case DRETURN : genReturn(frameState.dpop()); break; - case ARETURN : genReturn(frameState.apop()); break; - case RETURN : genReturn(null ); break; - case GETSTATIC : cpi = stream.readCPI(); genGetStatic(cpi, constantPool.lookupField(cpi, opcode)); break; - case PUTSTATIC : cpi = stream.readCPI(); genPutStatic(cpi, constantPool.lookupField(cpi, opcode)); break; - case GETFIELD : cpi = stream.readCPI(); genGetField(cpi, constantPool.lookupField(cpi, opcode)); break; - case PUTFIELD : cpi = stream.readCPI(); genPutField(cpi, constantPool.lookupField(cpi, opcode)); break; - case INVOKEVIRTUAL : cpi = stream.readCPI(); genInvokeVirtual(constantPool.lookupMethod(cpi, opcode), cpi, constantPool); break; - case INVOKESPECIAL : cpi = stream.readCPI(); genInvokeSpecial(constantPool.lookupMethod(cpi, opcode), null, cpi, constantPool); break; - case INVOKESTATIC : cpi = stream.readCPI(); genInvokeStatic(constantPool.lookupMethod(cpi, opcode), cpi, constantPool); break; - case INVOKEINTERFACE: cpi = stream.readCPI(); genInvokeInterface(constantPool.lookupMethod(cpi, opcode), cpi, constantPool); break; - case NEW : genNewInstance(stream.readCPI()); break; - case NEWARRAY : genNewTypeArray(stream.readLocalIndex()); break; - case ANEWARRAY : genNewObjectArray(stream.readCPI()); break; - case ARRAYLENGTH : genArrayLength(); break; - case ATHROW : genThrow(stream.currentBCI()); break; - case CHECKCAST : genCheckCast(); break; - case INSTANCEOF : genInstanceOf(); break; - case MONITORENTER : genMonitorEnter(frameState.apop(), stream.currentBCI()); break; - case MONITOREXIT : genMonitorExit(frameState.apop()); break; - case MULTIANEWARRAY : genNewMultiArray(stream.readCPI()); break; - case IFNULL : genIfNull(Condition.EQ); break; - case IFNONNULL : genIfNull(Condition.NE); break; - case GOTO_W : genGoto(stream.currentBCI(), stream.readFarBranchDest()); break; - case JSR_W : genJsr(stream.readFarBranchDest()); break; - case BREAKPOINT: - throw new CiBailout("concurrent setting of breakpoint"); - default: - throw new CiBailout("Unsupported opcode " + opcode + " (" + nameOf(opcode) + ") [bci=" + bci + "]"); - } - // Checkstyle: resume - } - - private void traceInstruction(int bci, int opcode, boolean blockStart) { - if (C1XOptions.TraceBytecodeParserLevel >= TRACELEVEL_INSTRUCTIONS && !TTY.isSuppressed()) { - StringBuilder sb = new StringBuilder(40); - sb.append(blockStart ? '+' : '|'); - if (bci < 10) { - sb.append(" "); - } else if (bci < 100) { - sb.append(' '); - } - sb.append(bci).append(": ").append(Bytecodes.nameOf(opcode)); - for (int i = bci + 1; i < stream.nextBCI(); ++i) { - sb.append(' ').append(stream.readUByte(i)); - } - log.println(sb.toString()); - } - } - - private void genArrayLength() { - frameState.ipush(append(new ArrayLength(frameState.apop(), graph))); - } - - /** - * Adds a block to the worklist, if it is not already in the worklist. - * This method will keep the worklist topologically stored (i.e. the lower - * DFNs are earlier in the list). - * @param block the block to add to the work list - */ - private void addToWorkList(Block block) { - if (!isOnWorkList(block)) { - markOnWorkList(block); - sortIntoWorkList(block); - } - } - - private void sortIntoWorkList(Block top) { - workList.offer(top); - } - - /** - * Removes the next block from the worklist. The list is sorted topologically, so the - * block with the lowest depth first number in the list will be removed and returned. - * @return the next block from the worklist; {@code null} if there are no blocks - * in the worklist - */ - private Block removeFromWorkList() { - return workList.poll(); - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/graph/IR.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/graph/IR.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,251 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.graph; - -import java.util.*; - -import com.oracle.graal.graph.*; -import com.oracle.max.graal.opt.*; -import com.oracle.max.graal.schedule.*; -import com.sun.c1x.*; -import com.sun.c1x.debug.*; -import com.sun.c1x.ir.*; -import com.sun.c1x.lir.*; -import com.sun.c1x.observer.*; -import com.sun.c1x.value.*; - -/** - * This class implements the overall container for the HIR (high-level IR) graph - * and directs its construction, optimization, and finalization. - */ -public class IR { - - /** - * The compilation associated with this IR. - */ - public final C1XCompilation compilation; - - /** - * The start block of this IR. - */ - public LIRBlock startBlock; - - /** - * The linear-scan ordered list of blocks. - */ - private List orderedBlocks; - - /** - * Creates a new IR instance for the specified compilation. - * @param compilation the compilation - */ - public IR(C1XCompilation compilation) { - this.compilation = compilation; - } - - public Map valueToBlock; - - /** - * Builds the graph, optimizes it, and computes the linear scan block order. - */ - public void build() { - if (C1XOptions.PrintTimers) { - C1XTimers.HIR_CREATE.start(); - } - - buildGraph(); - - if (C1XOptions.PrintTimers) { - C1XTimers.HIR_CREATE.stop(); - C1XTimers.HIR_OPTIMIZE.start(); - } - - Graph graph = compilation.graph; - - if (C1XOptions.OptCanonicalizer) { - new CanonicalizerPhase().apply(graph); - verifyAndPrint("After canonicalization"); - } - - // Split critical edges. - List nodes = graph.getNodes(); - for (int i = 0; i < nodes.size(); ++i) { - Node n = nodes.get(i); - if (Schedule.trueSuccessorCount(n) > 1) { - for (int j = 0; j < n.successors().size(); ++j) { - Node succ = n.successors().get(j); - if (Schedule.truePredecessorCount(succ) > 1) { - Anchor a = new Anchor(graph); - a.successors().setAndClear(1, n, j); - n.successors().set(j, a); - } - } - } - } - - Schedule schedule = new Schedule(graph); - List blocks = schedule.getBlocks(); - List lirBlocks = new ArrayList(); - Map map = new HashMap(); - for (Block b : blocks) { - LIRBlock block = new LIRBlock(b.blockID()); - map.put(b, block); - block.setInstructions(b.getInstructions()); - block.setLinearScanNumber(b.blockID()); - - block.setFirstInstruction(b.firstNode()); - block.setLastInstruction(b.lastNode()); - lirBlocks.add(block); - } - - for (Block b : blocks) { - for (Block succ : b.getSuccessors()) { - map.get(b).blockSuccessors().add(map.get(succ)); - } - - for (Block pred : b.getPredecessors()) { - map.get(b).blockPredecessors().add(map.get(pred)); - } - } - - orderedBlocks = lirBlocks; - valueToBlock = new HashMap(); - for (LIRBlock b : orderedBlocks) { - for (Node i : b.getInstructions()) { - valueToBlock.put(i, b); - } - } - startBlock = lirBlocks.get(0); - assert startBlock != null; - assert startBlock.blockPredecessors().size() == 0; - - ComputeLinearScanOrder clso = new ComputeLinearScanOrder(lirBlocks.size(), startBlock); - orderedBlocks = clso.linearScanOrder(); - this.compilation.stats.loopCount = clso.numLoops(); - - int z = 0; - for (LIRBlock b : orderedBlocks) { - b.setLinearScanNumber(z++); - } - - verifyAndPrint("After linear scan order"); - - if (C1XOptions.PrintTimers) { - C1XTimers.HIR_OPTIMIZE.stop(); - } - } - - private void buildGraph() { - // Graph builder must set the startBlock and the osrEntryBlock - new GraphBuilder(compilation, compilation.method, compilation.graph).build(false); - -// CompilerGraph duplicate = new CompilerGraph(); -// Map replacements = new HashMap(); -// replacements.put(compilation.graph.start(), duplicate.start()); -// duplicate.addDuplicate(compilation.graph.getNodes(), replacements); -// compilation.graph = duplicate; - - verifyAndPrint("After graph building"); - - DeadCodeElimination dce = new DeadCodeElimination(); - dce.apply(compilation.graph); - if (dce.deletedNodeCount > 0) { - verifyAndPrint("After dead code elimination"); - } - - if (C1XOptions.Inline) { - new Inlining(compilation, this).apply(compilation.graph); - } - - if (C1XOptions.PrintCompilation) { - TTY.print(String.format("%3d blocks | ", compilation.stats.blockCount)); - } - } - - /** - * Gets the linear scan ordering of blocks as a list. - * @return the blocks in linear scan order - */ - public List linearScanOrder() { - return orderedBlocks; - } - - private void print(boolean cfgOnly) { - if (!TTY.isSuppressed()) { - TTY.println("IR for " + compilation.method); - final InstructionPrinter ip = new InstructionPrinter(TTY.out()); - final BlockPrinter bp = new BlockPrinter(this, ip, cfgOnly); - //getHIRStartBlock().iteratePreOrder(bp); - } - } - - /** - * Verifies the IR and prints it out if the relevant options are set. - * @param phase the name of the phase for printing - */ - public void verifyAndPrint(String phase) { - if (C1XOptions.PrintHIR && !TTY.isSuppressed()) { - TTY.println(phase); - print(false); - } - - if (compilation.compiler.isObserved()) { - compilation.compiler.fireCompilationEvent(new CompilationEvent(compilation, phase, compilation.graph, true, false)); - } - } - - public void printGraph(String phase, Graph graph) { - if (C1XOptions.PrintHIR && !TTY.isSuppressed()) { - TTY.println(phase); - print(false); - } - - if (compilation.compiler.isObserved()) { - compilation.compiler.fireCompilationEvent(new CompilationEvent(compilation, phase, graph, true, false)); - } - } - - public int numLoops() { - return compilation.stats.loopCount; - } - - /** - * Gets the maximum number of locks in the graph's frame states. - */ - public final int maxLocks() { - int maxLocks = 0; - for (Node node : compilation.graph.getNodes()) { - if (node instanceof FrameState) { - int lockCount = ((FrameState) node).locksSize(); - if (lockCount > maxLocks) { - maxLocks = lockCount; - } - } - } - return maxLocks; - } - - public Instruction getHIRStartBlock() { - return (Instruction) compilation.graph.start().successors().get(0); - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/graph/Inlining.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/graph/Inlining.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,288 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.graph; - -import java.lang.reflect.*; -import java.util.*; - -import com.oracle.graal.graph.*; -import com.sun.c1x.*; -import com.sun.c1x.ir.*; -import com.sun.c1x.value.*; -import com.sun.cri.ci.*; -import com.sun.cri.ri.*; - - -public class Inlining extends Phase { - - private final C1XCompilation compilation; - private final IR ir; - - private final Queue invokes = new ArrayDeque(); - private final Queue methods = new ArrayDeque(); - private int inliningSize; - - public Inlining(C1XCompilation compilation, IR ir) { - this.compilation = compilation; - this.ir = ir; - } - - private void addToQueue(Invoke invoke, RiMethod method) { - invokes.add(invoke); - methods.add(method); - inliningSize += method.code().length; - } - - @Override - protected void run(Graph graph) { - if (!C1XOptions.Inline) { - return; - } - - inliningSize = compilation.method.code().length; - int iterations = C1XOptions.MaximumRecursiveInlineLevel; - do { - for (Node node : graph.getNodes()) { - if (node instanceof Invoke) { - Invoke invoke = (Invoke) node; - RiMethod target = invoke.target; - if (!checkInliningConditions(invoke) || !target.isResolved() || Modifier.isNative(target.accessFlags())) { - continue; - } - if (target.canBeStaticallyBound()) { - if (checkInliningConditions(invoke.target)) { - addToQueue(invoke, invoke.target); - } - } else { - RiMethod concrete = invoke.target.holder().uniqueConcreteMethod(invoke.target); - if (concrete != null && concrete.isResolved() && !Modifier.isNative(concrete.accessFlags())) { - if (checkInliningConditions(concrete)) { - if (C1XOptions.TraceInlining) { - System.out.println("registering concrete method assumption..."); - } - compilation.assumptions.recordConcreteMethod(invoke.target, concrete); - addToQueue(invoke, concrete); - } - } - } - if (inliningSize > C1XOptions.MaximumInstructionCount) { - break; - } - } - } - - assert invokes.size() == methods.size(); - if (invokes.isEmpty()) { - break; - } - - Invoke invoke; - while ((invoke = invokes.poll()) != null) { - RiMethod method = methods.remove(); - inlineMethod(invoke, method); - } - DeadCodeElimination dce = new DeadCodeElimination(); - dce.apply(graph); - if (dce.deletedNodeCount > 0) { - ir.verifyAndPrint("After dead code elimination"); - } - ir.verifyAndPrint("After inlining iteration"); - - if (inliningSize > C1XOptions.MaximumInstructionCount) { - if (C1XOptions.TraceInlining) { - System.out.println("inlining stopped: MaximumInstructionCount reached"); - } - break; - } - } while(--iterations > 0); - } - - private boolean checkInliningConditions(Invoke invoke) { - String name = invoke.id() + ": " + CiUtil.format("%H.%n(%p):%r", invoke.target, false); - if (invoke.predecessors().size() == 0) { - if (C1XOptions.TraceInlining) { - System.out.println("not inlining " + name + " because the invoke is dead code"); - } - return false; - } - return true; - } - - private boolean checkInliningConditions(RiMethod method) { - String name = null; - if (C1XOptions.TraceInlining) { - name = CiUtil.format("%H.%n(%p):%r", method, false) + " (" + method.code().length + " bytes)"; - } - if (method.code().length > C1XOptions.MaximumInlineSize) { - if (C1XOptions.TraceInlining) { - System.out.println("not inlining " + name + " because of code size"); - } - return false; - } - if (!method.holder().isInitialized()) { - if (C1XOptions.TraceInlining) { - System.out.println("not inlining " + name + " because of non-initialized class"); - } - return false; - } - return true; - } - - private void inlineMethod(Invoke invoke, RiMethod method) { - String name = invoke.id() + ": " + CiUtil.format("%H.%n(%p):%r", method, false) + " (" + method.code().length + " bytes)"; - FrameState stateAfter = invoke.stateAfter(); - Instruction exceptionEdge = invoke.exceptionEdge(); - - if (C1XOptions.TraceInlining) { - System.out.printf("Building graph for %s, locals: %d, stack: %d\n", name, method.maxLocals(), method.maxStackSize()); - } - - CompilerGraph graph = new CompilerGraph(); - new GraphBuilder(compilation, method, graph).build(true); - - boolean withReceiver = !Modifier.isStatic(method.accessFlags()); - - int argumentCount = method.signature().argumentCount(false); - Value[] parameters = new Value[argumentCount + (withReceiver ? 1 : 0)]; - int slot = withReceiver ? 1 : 0; - int param = withReceiver ? 1 : 0; - for (int i = 0; i < argumentCount; i++) { - parameters[param++] = invoke.argument(slot); - slot += method.signature().argumentKindAt(i).sizeInSlots(); - } - if (withReceiver) { - parameters[0] = invoke.argument(0); - } - - HashMap replacements = new HashMap(); - ArrayList nodes = new ArrayList(); - ArrayList frameStates = new ArrayList(); - Return returnNode = null; - Unwind unwindNode = null; - StartNode startNode = graph.start(); - for (Node node : graph.getNodes()) { - if (node != null) { - if (node instanceof StartNode) { - assert startNode == node; - } else if (node instanceof Local) { - replacements.put(node, parameters[((Local) node).index()]); - } else { - nodes.add(node); - if (node instanceof Return) { - returnNode = (Return) node; - } else if (node instanceof Unwind) { - unwindNode = (Unwind) node; - } else if (node instanceof FrameState) { - frameStates.add(node); - } - } - } - } - - if (C1XOptions.TraceInlining) { - ir.printGraph("Subgraph " + CiUtil.format("%H.%n(%p):%r", method, false), graph); - System.out.println("inlining " + name + ": " + frameStates.size() + " frame states, " + nodes.size() + " nodes"); - } - - assert invoke.predecessors().size() == 1 : "size: " + invoke.predecessors().size(); - Instruction pred; - if (withReceiver) { - pred = new NullCheck(parameters[0], compilation.graph); - } else { - pred = new Merge(compilation.graph); - } - invoke.predecessors().get(0).successors().replace(invoke, pred); - replacements.put(startNode, pred); - - Map duplicates = compilation.graph.addDuplicate(nodes, replacements); - - if (returnNode != null) { - List usages = new ArrayList(invoke.usages()); - for (Node usage : usages) { - if (returnNode.result() instanceof Local) { - usage.inputs().replace(invoke, replacements.get(returnNode.result())); - } else { - usage.inputs().replace(invoke, duplicates.get(returnNode.result())); - } - } - Node returnDuplicate = duplicates.get(returnNode); - returnDuplicate.inputs().clearAll(); - - assert returnDuplicate.predecessors().size() == 1; - Node returnPred = returnDuplicate.predecessors().get(0); - int index = returnDuplicate.predecessorsIndex().get(0); - returnPred.successors().setAndClear(index, invoke, 0); - returnDuplicate.delete(); - } - -// if (invoke.next() instanceof Merge) { -// ((Merge) invoke.next()).removePhiPredecessor(invoke); -// } -// invoke.successors().clearAll(); - invoke.inputs().clearAll(); - invoke.setExceptionEdge(null); -// invoke.delete(); - - - if (exceptionEdge != null) { - if (unwindNode != null) { - assert unwindNode.predecessors().size() == 1; - assert exceptionEdge.successors().size() == 1; - ExceptionObject obj = (ExceptionObject) exceptionEdge; - - List usages = new ArrayList(obj.usages()); - for (Node usage : usages) { - if (replacements.containsKey(unwindNode.exception())) { - usage.inputs().replace(obj, replacements.get(unwindNode.exception())); - } else { - usage.inputs().replace(obj, duplicates.get(unwindNode.exception())); - } - } - Node unwindDuplicate = duplicates.get(unwindNode); - unwindDuplicate.inputs().clearAll(); - - assert unwindDuplicate.predecessors().size() == 1; - Node unwindPred = unwindDuplicate.predecessors().get(0); - int index = unwindDuplicate.predecessorsIndex().get(0); - unwindPred.successors().setAndClear(index, obj, 0); - - obj.inputs().clearAll(); - obj.delete(); - unwindDuplicate.delete(); - - } - } - - // adjust all frame states that were copied - if (frameStates.size() > 0) { - FrameState outerFrameState = stateAfter.duplicateModified(invoke.bci, invoke.kind); - for (Node frameState : frameStates) { - ((FrameState) duplicates.get(frameState)).setOuterFrameState(outerFrameState); - } - } - - if (C1XOptions.TraceInlining) { - ir.verifyAndPrint("After inlining " + CiUtil.format("%H.%n(%p):%r", method, false)); - } - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/graph/JSRNotSupportedBailout.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/graph/JSRNotSupportedBailout.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.graph; - -import com.sun.cri.ci.*; - - -public class JSRNotSupportedBailout extends CiBailout{ - private static final long serialVersionUID = -7476925652727154272L; - - public JSRNotSupportedBailout() { - super("jsr/ret not supported"); - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/graph/MemoryMap.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/graph/MemoryMap.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,167 +0,0 @@ -/* - * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.graph; - -import static java.lang.reflect.Modifier.*; - -import java.util.*; - -import com.sun.c1x.ir.*; -import com.sun.cri.ri.*; - -/** - * The {@code MemoryMap} class is an approximation of memory that is used redundant load and - * store elimination. In C1, tracking of fields of new objects' fields was precise, - * while tracking of other fields is managed at the offset granularity (i.e. a write of a field with offset - * {@code off} will "overwrite" all fields with the offset {@code off}. However, C1X distinguishes all - * loaded fields as separate locations. Static fields have just one location, while instance fields are - * tracked for at most one instance object. Loads or stores of unloaded fields kill all memory locations. - * An object is no longer "new" if it is stored into a field or array. - * - * @author Ben L. Titzer - */ -public class MemoryMap { - - private final HashMap objectMap = new HashMap(); - private final HashMap valueMap = new HashMap(); - private final IdentityHashMap newObjects = new IdentityHashMap(); - - /** - * Kills all memory locations. - */ - public void kill() { - objectMap.clear(); - valueMap.clear(); - newObjects.clear(); - } - - /** - * The specified instruction has just escaped, it can no longer be considered a "new object". - * @param x the instruction that just escaped - */ - public void storeValue(Value x) { - newObjects.remove(x); - } - - /** - * Record a newly allocated object. - * @param n the instruction generating the new object - */ - public void newInstance(NewInstance n) { - newObjects.put(n, n); - } - - /** - * Look up a load for load elimination, and put this load into the load elimination map. - * @param load the instruction representing the load - * @return a reference to the previous instruction that already loaded the value, if it is available; the - * {@code load} parameter otherwise - */ - public Value load(LoadField load) { - if (!load.isLoaded()) { - // the field is not loaded, kill everything, because it will need to be resolved - kill(); - return load; - } - RiField field = load.field(); - if (load.isStatic()) { - // the field is static, look in the static map - Value r = valueMap.get(field); - if (r != null) { - return r; - } - valueMap.put(field, load); - } else { - // see if the value for this object for this field is in the map - if (objectMap.get(field) == load.object()) { - return valueMap.get(field); - } - objectMap.put(field, load.object()); - valueMap.put(field, load); - } - - return load; // load cannot be eliminated - } - - /** - * Insert a new result for a load into the memory map. - * @param load the load instruction - * @param result the result that the load instruction should produce - */ - public void setResult(LoadField load, Value result) { - if (load.isLoaded()) { - RiField field = load.field(); - if (load.isStatic()) { - // the field is static, put it in the static map - valueMap.put(field, result); - } else { - // put the result for the loaded object into the map - objectMap.put(field, load.object()); - valueMap.put(field, result); - } - } - } - - /** - * Look up a store for store elimination, and put this store into the load elimination map. - * @param store the store instruction to put into the map - * @return {@code null} if the store operation is redundant; the {@code store} parameter - * otherwise - */ - public StoreField store(StoreField store) { - if (!store.isLoaded()) { - // the field is not loaded, kill everything, because it will need to be resolved - kill(); - return store; - } - RiField field = store.field(); - Value value = store.value(); - if (store.isStatic()) { - // the field is static, overwrite it into the static map - valueMap.put(field, value); - } else { - if (newObjects.containsKey(store.object())) { - // this is a store to a new object's field - if (fieldHasNoStores(field) && value.isConstant() && value.asConstant().isDefaultValue()) { - // this is a redundant initialization of a new object's field that has not been assigned to - return null; - } - } - Value obj = objectMap.get(field); - if (obj == store.object()) { - // is this a redundant store? - if (value == valueMap.get(field) && !isVolatile(field.accessFlags())) { - return null; - } - } - objectMap.put(field, store.object()); - valueMap.put(field, value); - } - storeValue(value); // the value stored just escaped - return store; // the store cannot be eliminated - } - - private boolean fieldHasNoStores(RiField field) { - return objectMap.get(field) == null; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/graph/package-info.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/graph/package-info.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,153 +0,0 @@ -/* - * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/** - *

IR Graph building

- * - * The {@link com.sun.c1x.graph.IR} class drives the generation of the HIR graph for a method, making use of other - * utility classes in this package. - * - * The graph building is separated into a basic build phase ({@link com.sun.c1x.graph.IR#buildGraph} method)and - * (currently) two optimization phases ({@link com.sun.c1x.graph.IR#optimize1} and - * {@link com.sun.c1x.graph.IR#optimize2}) although the basic phase also does some (basic) optimizations. - * - *

Basic Graph Build Phase

- * - * {@code IR.buildGraph} creates an {@link com.sun.c1x.ir.IRScope topScope} object, - * that represents a context for inlining, and then invokes the constructor for the - * {@link com.sun.c1x.graph.GraphBuilder} class, passing the {@link com.sun.c1x.C1XCompilation}, and {@code IR} - * instances, which are cached. The following support objects are created in the constructor: - * - *
    - *
  • {@code memoryMap}: an instance of {@link com.sun.c1x.graph.MemoryMap} - *
  • {@code localValueMap}: an instance of {@link com.sun.c1x.opt.ValueMap} - *
  • {@code canonicalizer}: an instance of {@link com.sun.c1x.opt.Canonicalizer} - *
- * - * Now the {@link com.sun.c1x.graph.GraphBuilder#build} is invoked with {@code topScope} as argument. - * - *

{@code GraphBuilder.build}

- * - *
    - *
  1. The {@link com.sun.c1x.graph.IR#startBlock} field of the cached {@link com.sun.c1x.graph.IR} instance is set to a newly created - * {@link com.sun.c1x.ir.BlockBegin} node, with bytecode index 0 and then the {@link com.sun.c1x.graph.BlockMap} is - * constructed by calling {@link com.sun.c1x.C1XCompilation#getBlockMap}. This behaves slightly differently depending on - * whether this is an OSR compilation. If so, a new {@link com.sun.c1x.ir.BlockBegin} node is added to the map at the OSR bytecode - * index. The map is then built by the{@link com.sun.c1x.graph.BlockMap#build}, which takes a boolean argument that - * controls whether a second pass is made over the bytecodes to compute stores in loops. This always false for an OSR - * compilation (why?). Otherwise, it is only true if enabled by the {@link com.sun.c1x.C1XOptions#PhiLoopStores} - * compilation option. FInally some unneeded state from the map is removed by the {@link com.sun.c1x.graph.BlockMap#cleanup} method, and - * the statistics are updated. - *
  2. - * - *
  3. Next the {@link com.sun.c1x.graph.GraphBuilder#pushRootScope} method is called, with the passed-in {@link com.sun.c1x.ir.IRScope} - * object, the {@link com.sun.c1x.graph.BlockMap} returned by build and the {@code startBlock}. (Note: Unlike - * {@link com.sun.c1x.graph.GraphBuilder#pushScope}, this method does not propagate the - * {@link com.sun.c1x.graph.BlockMap#storesInLoops} field to the {@link com.sun.c1x.ir.IRScope} object, which means that - * {@link com.sun.c1x.ir.BlockBegin#insertLoopPhis} will always get null for this value. Is this a bug?). - * {@link com.sun.c1x.graph.GraphBuilder#pushRootScope} initializes the {@link com.sun.c1x.graph.GraphBuilder#scopeData} field with a - * {@link com.sun.c1x.graph.ScopeData} instance, with null parent. The - * {@link com.sun.c1x.graph.GraphBuilder#compilation} instance is called to get an {@link com.sun.cri.ri.RiConstantPool} - * , which is C1X's interface to constant pool information. The {@link com.sun.c1x.graph.GraphBuilder#curBlock} field is - * set to the {@code startBlock}. - *

    - * - * Now a {@link com.sun.c1x.value.FrameState initialState} object is created by - * {@link com.sun.c1x.graph.GraphBuilder#stateAtEntry}. If the method is not static, then a {@link com.sun.c1x.ir.Local} - * instance is created at index 0. Since the receiver cannot be {@code null}, the - * {@link com.sun.c1x.ir.Value.Flag#NonNull} flag is set. Additional {@link com.sun.c1x.ir.Local} instances are created for the - * arguments to the method. The index is incremented by the number of slots occupied by the - * {@link com.sun.cri.ci.CiKind} corresponding to the argument type. All the {@link com.sun.c1x.ir.Local} instances are stored in the - * {@link com.sun.c1x.value.FrameState} using the {@link com.sun.c1x.value.FrameState#storeLocal} method. This {@link com.sun.c1x.value.FrameState} is then - * merged into the {@link com.sun.c1x.ir.BlockBegin#stateBefore} for the {@code startBlock}, which just results in a - * copy since {@code stateBefore} will be {@code null}. - *

  4. - *
  5. - * This step sets up three instance fields: {@link com.sun.c1x.graph.GraphBuilder#curBlock} and - * {@link com.sun.c1x.graph.GraphBuilder#lastInstr} to {@code startBlock} and - * {@link com.sun.c1x.graph.GraphBuilder#curState} to {@code initialState}. (N.B. the setting of {@code curBlock} is - * redundant as it is done in {@link com.sun.c1x.graph.GraphBuilder#pushRootScope}). - *
  6. - *
  7. - * Step 4 contains special handling for synchronized methods (TBD), otherwise it calls - * {@link com.sun.c1x.graph.GraphBuilder#finishStartBlock} which adds a {@link com.sun.c1x.ir.Base} block as the end of - * the {@code startBlock}. The {@link com.sun.c1x.ir.Base} block has one successor set to the (entry) block with flag - * {@link com.sun.c1x.ir.BlockBegin.BlockFlag#StandardEntry}, that was created by {@link com.sun.c1x.graph.BlockMap#build} (and possibly a - * successor to an OSREntry block). - *
  8. - *
  9. - * Then the {@link com.sun.c1x.ir.IRScope#lockStackSize} is computed. (TBD) - *
  10. - *
  11. - * Then the method is checked for being intrinsic, i.e., one that has a hard-wired implementation known to C1X. If so, - * and {@link com.sun.c1x.C1XOptions#OptIntrinsify} is set, an attempt is made to inline it (TBD). Otherwise, or if the - * intrinsification fails, normal processing continues by adding the entry block to the - * {@link com.sun.c1x.graph.ScopeData} work list (kept topologically sorted) and calling - * {@link com.sun.c1x.graph.GraphBuilder#iterateAllBlocks}. - *
  12. - *
  13. - * Finally there is some cleanup code for synchronized blocks and OSR compilations. - *
  14. - *
- * - *

{@link com.sun.c1x.graph.GraphBuilder#iterateAllBlocks}

- * {@link com.sun.c1x.graph#iterateAllBlocks} repeatedly removes a block from the work list and, if not already visited, marks it so, - * kills the current memory map, sets {@link com.sun.c1x.graph.GraphBuilder#curBlock}, {@link com.sun.c1x.graph.GraphBuilder#curState} and {@link com.sun.c1x.graph.GraphBuilder#lastInstr} and then calls - * {@link com.sun.c1x.graph.GraphBuilder#iterateBytecodesForBlock}. - * - * This process continues until all the blocks have been visited (processed) after which control returns to {@code - * build}. - *

- - *

{@link com.sun.c1x.graph.GraphBuilder#iterateBytecodesForBlock}

- * - * {@link com.sun.c1x.graph.GraphBuilder#iterateBytecodesForBlock} performs an abstract interpretation of the bytecodes in the block, appending new - * nodes as necessary, until the last added node is an instance of {@link com.sun.c1x.ir.BlockEnd}. (Note: It has an - * explicit check for finding a new {@link com.sun.c1x.ir.BlockBegin} before a {@link com.sun.c1x.ir.BlockEnd} but - * {@link com.sun.c1x.graph.BlockMap#moveSuccessorLists} has a similar check so this may be redundant). For example, - * consider the following bytecodes: - * - *
- * 
- *         0: iconst_0
- *         1: istore_2
- *         2: goto 22
- * 
- * 
- * - * The {@code iconst_0} bytecode causes a {@link com.sun.c1x.ir.Constant} node representing zero to be pushed on the - * {@link com.sun.c1x.graph.GraphBuilder#curState} stack and the node to be appended to the {@link com.sun.c1x.ir.BlockBegin} (entry) node associated with index 0. - * The {@code istore_2} causes the node to be popped of the stack and stored in the local slot 2. No IR node is - * generated for the {@code istore_2}. The {@code goto} creates a {@link com.sun.c1x.ir.Goto} node which is a subclass - * of {@link com.sun.c1x.ir.BlockEnd}, so this terminates the iteration. As part of termination the {@link com.sun.c1x.ir.Goto} node is marked as the - * end node of the current block and the {@link com.sun.c1x.value.FrameState} is propagated to the successor node(s) by merging any - * existing {@link com.sun.c1x.value.FrameState} with the current state. If the target is a loop header node this involves inserting - * {@link com.sun.c1x.ir.Phi} nodes. Finally, the target node is added to the {@code scopeData} work list. - *

- * - * - * @author Ben Titzer - * @author Mick Jordan - * - */ -package com.sun.c1x.graph; diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/AccessArray.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/AccessArray.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.ir; - -import com.oracle.graal.graph.*; -import com.sun.cri.ci.*; - -/** - * This the base class of all array operations. - */ -public abstract class AccessArray extends StateSplit { - - private static final int INPUT_COUNT = 1; - private static final int INPUT_ARRAY = 0; - - private static final int SUCCESSOR_COUNT = 0; - - @Override - protected int inputCount() { - return super.inputCount() + INPUT_COUNT; - } - - @Override - protected int successorCount() { - return super.successorCount() + SUCCESSOR_COUNT; - } - - /** - * The instruction that produces the array object. - */ - public Value array() { - return (Value) inputs().get(super.inputCount() + INPUT_ARRAY); - } - - public Value setArray(Value n) { - return (Value) inputs().set(super.inputCount() + INPUT_ARRAY, n); - } - - /** - * Creates a new AccessArray instruction. - * @param kind the type of the result of this instruction - * @param array the instruction that produces the array object value - * @param stateBefore the frame state before the instruction - * @param inputCount - * @param successorCount - * @param graph - */ - public AccessArray(CiKind kind, Value array, int inputCount, int successorCount, Graph graph) { - super(kind, inputCount + INPUT_COUNT, successorCount + SUCCESSOR_COUNT, graph); - setArray(array); - } - -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/AccessField.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/AccessField.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,110 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.ir; - -import java.lang.reflect.*; - -import com.oracle.graal.graph.*; -import com.sun.cri.ci.*; -import com.sun.cri.ri.*; - -/** - * The base class of all instructions that access fields. - */ -public abstract class AccessField extends StateSplit { - - private static final int INPUT_COUNT = 1; - private static final int INPUT_OBJECT = 0; - - private static final int SUCCESSOR_COUNT = 0; - - @Override - protected int inputCount() { - return super.inputCount() + INPUT_COUNT; - } - - @Override - protected int successorCount() { - return super.successorCount() + SUCCESSOR_COUNT; - } - - /** - * The instruction that produces the receiver object of this field access (for instance field accesses). - */ - public Value object() { - return (Value) inputs().get(super.inputCount() + INPUT_OBJECT); - } - - public Value setObject(Value n) { - return (Value) inputs().set(super.inputCount() + INPUT_OBJECT, n); - } - - protected final RiField field; - - /** - * Constructs a new access field object. - * @param kind the result kind of the access - * @param object the instruction producing the receiver object - * @param field the compiler interface representation of the field - * @param inputCount - * @param successorCount - * @param graph - */ - public AccessField(CiKind kind, Value object, RiField field, int inputCount, int successorCount, Graph graph) { - super(kind, inputCount + INPUT_COUNT, successorCount + SUCCESSOR_COUNT, graph); - this.field = field; - setObject(object); - } - - /** - * Gets the compiler interface field for this field access. - * @return the compiler interface field for this field access - */ - public RiField field() { - return field; - } - - /** - * Checks whether this field access is an access to a static field. - * @return {@code true} if this field access is to a static field - */ - public boolean isStatic() { - return Modifier.isStatic(field.accessFlags()); - } - - /** - * Checks whether the class of the field of this access is loaded. - * @return {@code true} if the class is loaded - */ - public boolean isLoaded() { - return field.isResolved(); - } - - /** - * Checks whether this field is declared volatile. - * @return {@code true} if the field is resolved and declared volatile - */ - public boolean isVolatile() { - return isLoaded() && Modifier.isVolatile(field.accessFlags()); - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/AccessIndexed.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/AccessIndexed.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,101 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.ir; - -import com.oracle.graal.graph.*; -import com.sun.cri.ci.*; - -/** - * The {@code AccessIndexed} class is the base class of instructions that read or write - * elements of an array. - */ -public abstract class AccessIndexed extends AccessArray { - - private static final int INPUT_COUNT = 2; - private static final int INPUT_INDEX = 0; - private static final int INPUT_LENGTH = 1; - - private static final int SUCCESSOR_COUNT = 0; - - @Override - protected int inputCount() { - return super.inputCount() + INPUT_COUNT; - } - - @Override - protected int successorCount() { - return super.successorCount() + SUCCESSOR_COUNT; - } - - /** - * The instruction producing the index into the array. - */ - public Value index() { - return (Value) inputs().get(super.inputCount() + INPUT_INDEX); - } - - public Value setIndex(Value n) { - return (Value) inputs().set(super.inputCount() + INPUT_INDEX, n); - } - - /** - * The instruction that produces the length of the array. - */ - public Value length() { - return (Value) inputs().get(super.inputCount() + INPUT_LENGTH); - } - - public Value setLength(Value n) { - return (Value) inputs().set(super.inputCount() + INPUT_LENGTH, n); - } - - private final CiKind elementType; - - /** - * Create an new AccessIndexed instruction. - * @param kind the result kind of the access - * @param array the instruction producing the array - * @param index the instruction producing the index - * @param length the instruction producing the length (used in bounds check elimination?) - * @param elementKind the type of the elements of the array - * @param stateBefore the state before executing this instruction - * @param inputCount - * @param successorCount - * @param graph - */ - AccessIndexed(CiKind kind, Value array, Value index, Value length, CiKind elementKind, int inputCount, int successorCount, Graph graph) { - super(kind, array, inputCount + INPUT_COUNT, successorCount + SUCCESSOR_COUNT, graph); - setIndex(index); - setLength(length); - this.elementType = elementKind; - } - - /** - * Gets the element type of the array. - * @return the element type - */ - public CiKind elementKind() { - return elementType; - } - -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/AccessMonitor.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/AccessMonitor.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,93 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.ir; - -import com.oracle.graal.graph.*; -import com.sun.cri.ci.*; - -/** - * The {@code AccessMonitor} instruction is the base class of both monitor acquisition and release. - */ -public abstract class AccessMonitor extends StateSplit { - - private static final int INPUT_COUNT = 2; - private static final int INPUT_OBJECT = 0; - private static final int INPUT_LOCK_ADDRESS = 1; - - private static final int SUCCESSOR_COUNT = 0; - - @Override - protected int inputCount() { - return super.inputCount() + INPUT_COUNT; - } - - @Override - protected int successorCount() { - return super.successorCount() + SUCCESSOR_COUNT; - } - - /** - * The instruction producing the object locked or unlocked by this instruction. - */ - public Value object() { - return (Value) inputs().get(super.inputCount() + INPUT_OBJECT); - } - - public Value setObject(Value n) { - return (Value) inputs().set(super.inputCount() + INPUT_OBJECT, n); - } - - /** - * The instruction producing the address of the lock object. - */ - public Value lockAddress() { - return (Value) inputs().get(super.inputCount() + INPUT_LOCK_ADDRESS); - } - - public Value setLockAddress(Value n) { - return (Value) inputs().set(super.inputCount() + INPUT_LOCK_ADDRESS, n); - } - - /** - * The lock number of this monitor access. - */ - public final int lockNumber; - - /** - * Creates a new AccessMonitor instruction. - * - * @param object the instruction producing the object - * @param lockAddress the address of the on-stack lock object or {@code null} if the runtime does not place locks on the stack - * @param stateBefore the state before executing the monitor operation - * @param lockNumber the number of the lock being acquired - * @param inputCount - * @param successorCount - * @param graph - */ - public AccessMonitor(Value object, Value lockAddress, int lockNumber, int inputCount, int successorCount, Graph graph) { - super(CiKind.Illegal, inputCount + INPUT_COUNT, successorCount + SUCCESSOR_COUNT, graph); - this.lockNumber = lockNumber; - setObject(object); - setLockAddress(lockAddress); - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/Anchor.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/Anchor.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.ir; - -import com.oracle.graal.graph.*; -import com.sun.c1x.debug.*; -import com.sun.cri.ci.*; - -/** - * The {@code Anchor} instruction represents the end of a block with an unconditional jump to another block. - */ -public final class Anchor extends BlockEnd { - - private static final int INPUT_COUNT = 0; - private static final int SUCCESSOR_COUNT = 0; - - /** - * Constructs a new Anchor instruction. - * @param graph - */ - public Anchor(Graph graph) { - super(CiKind.Illegal, 1, INPUT_COUNT, SUCCESSOR_COUNT, graph); - } - - @Override - public void accept(ValueVisitor v) { - v.visitAnchor(this); - } - - @Override - public void print(LogStream out) { - out.print("anchor ").print(defaultSuccessor()); - } - - @Override - public Node copy(Graph into) { - Anchor x = new Anchor(into); - return x; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/And.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/And.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,111 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.ir; - -import com.oracle.graal.graph.*; -import com.oracle.max.graal.opt.CanonicalizerPhase.*; -import com.sun.cri.bytecode.*; -import com.sun.cri.ci.*; - -public final class And extends Logic { - private static final AndCanonicalizerOp CANONICALIZER = new AndCanonicalizerOp(); - - /** - * @param opcode - * @param x - * @param y - * @param graph - */ - public And(CiKind kind, Value x, Value y, Graph graph) { - super(kind, kind == CiKind.Int ? Bytecodes.IAND : Bytecodes.LAND, x, y, graph); - } - - @Override - public String shortName() { - return "&"; - } - - @Override - public Node copy(Graph into) { - And x = new And(kind, null, null, into); - return x; - } - - @SuppressWarnings("unchecked") - @Override - public T lookup(Class clazz) { - if (clazz == CanonicalizerOp.class) { - return (T) CANONICALIZER; - } - return super.lookup(clazz); - } - - private static class AndCanonicalizerOp implements CanonicalizerOp { - @Override - public Node canonical(Node node) { - assert node instanceof And; - And and = (And) node; - CiKind kind = and.kind; - Graph graph = and.graph(); - Value x = and.x(); - Value y = and.y(); - if (x == y) { - return x; - } - if (x.isConstant() && !y.isConstant()) { - and.swapOperands(); - Value t = y; - y = x; - x = t; - } - if (x.isConstant()) { - if (kind == CiKind.Int) { - return Constant.forInt(x.asConstant().asInt() & y.asConstant().asInt(), graph); - } else { - assert kind == CiKind.Long; - return Constant.forLong(x.asConstant().asLong() & y.asConstant().asLong(), graph); - } - } else if (y.isConstant()) { - if (kind == CiKind.Int) { - int c = y.asConstant().asInt(); - if (c == -1) { - return x; - } - if (c == 0) { - return Constant.forInt(0, graph); - } - } else { - assert kind == CiKind.Long; - long c = y.asConstant().asLong(); - if (c == -1) { - return x; - } - if (c == 0) { - return Constant.forLong(0, graph); - } - } - } - return and; - } - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/Arithmetic.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/Arithmetic.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,88 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.ir; - -import com.oracle.graal.graph.*; -import com.sun.c1x.debug.*; -import com.sun.cri.bytecode.*; -import com.sun.cri.ci.*; - -/** - * The {@code ArithmeticOp} class represents arithmetic operations such as addition, subtraction, etc. - */ -public final class Arithmetic extends Binary { - - private static final int INPUT_COUNT = 0; - private static final int SUCCESSOR_COUNT = 0; - - private final boolean canTrap; - private final boolean isStrictFP; - - /** - * Creates a new arithmetic operation. - * @param opcode the bytecode opcode - * @param kind the result kind of the operation - * @param x the first input instruction - * @param y the second input instruction - * @param isStrictFP indicates this operation has strict rounding semantics - * @param stateBefore the state for instructions that may trap - */ - public Arithmetic(int opcode, CiKind kind, Value x, Value y, boolean isStrictFP, boolean canTrap, Graph graph) { - super(kind, opcode, x, y, INPUT_COUNT, SUCCESSOR_COUNT, graph); - this.isStrictFP = isStrictFP; - this.canTrap = canTrap; - } - - /** - * Checks whether this instruction has strict fp semantics. - * @return {@code true} if this instruction has strict fp semantics - */ - public boolean isStrictFP() { - return isStrictFP; - } - - @Override - public void accept(ValueVisitor v) { - v.visitArithmetic(this); - } - - public boolean isCommutative() { - return Bytecodes.isCommutative(opcode); - } - - @Override - public void print(LogStream out) { - out.print(x()).print(' ').print(Bytecodes.operator(opcode)).print(' ').print(y()); - } - - @Override - public String shortName() { - return Bytecodes.operator(opcode); - } - - @Override - public Node copy(Graph into) { - Arithmetic x = new Arithmetic(opcode, kind, null, null, isStrictFP, canTrap, into); - return x; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/ArrayLength.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/ArrayLength.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,101 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.ir; - -import com.oracle.graal.graph.*; -import com.sun.c1x.debug.*; -import com.sun.c1x.util.*; -import com.sun.cri.bytecode.*; -import com.sun.cri.ci.*; - -/** - * The {@code ArrayLength} instruction gets the length of an array. - */ -public final class ArrayLength extends FloatingNode { - - private static final int INPUT_COUNT = 1; - private static final int INPUT_ARRAY = 0; - - private static final int SUCCESSOR_COUNT = 0; - - @Override - protected int inputCount() { - return super.inputCount() + INPUT_COUNT; - } - - @Override - protected int successorCount() { - return super.successorCount() + SUCCESSOR_COUNT; - } - - /** - * The instruction that produces the array object. - */ - public Value array() { - return (Value) inputs().get(super.inputCount() + INPUT_ARRAY); - } - - public Value setArray(Value n) { - return (Value) inputs().set(super.inputCount() + INPUT_ARRAY, n); - } - - /** - * Constructs a new ArrayLength instruction. - * @param array the instruction producing the array - * @param newFrameState the state after executing this instruction - */ - public ArrayLength(Value array, Graph graph) { - super(CiKind.Int, INPUT_COUNT, SUCCESSOR_COUNT, graph); - setArray(array); - } - - @Override - public void accept(ValueVisitor v) { - v.visitArrayLength(this); - } - - @Override - public int valueNumber() { - return Util.hash1(Bytecodes.ARRAYLENGTH, array()); - } - - @Override - public boolean valueEqual(Node i) { - if (i instanceof ArrayLength) { - ArrayLength o = (ArrayLength) i; - return array() == o.array(); - } - return false; - } - - @Override - public void print(LogStream out) { - out.print(array()).print(".length"); - } - - @Override - public Node copy(Graph into) { - ArrayLength x = new ArrayLength(null, into); - return x; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/Binary.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/Binary.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,115 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.ir; - -import com.oracle.graal.graph.*; -import com.sun.c1x.util.*; -import com.sun.cri.bytecode.*; -import com.sun.cri.ci.*; - -/** - * The {@code Op2} class is the base of arithmetic and logic operations with two inputs. - */ -public abstract class Binary extends FloatingNode { - - private static final int INPUT_COUNT = 2; - private static final int INPUT_X = 0; - private static final int INPUT_Y = 1; - - private static final int SUCCESSOR_COUNT = 0; - - @Override - protected int inputCount() { - return super.inputCount() + INPUT_COUNT; - } - - @Override - protected int successorCount() { - return super.successorCount() + SUCCESSOR_COUNT; - } - - /** - * The first input to this instruction. - */ - public Value x() { - return (Value) inputs().get(super.inputCount() + INPUT_X); - } - - public Value setX(Value n) { - return (Value) inputs().set(super.inputCount() + INPUT_X, n); - } - - /** - * The second input to this instruction. - */ - public Value y() { - return (Value) inputs().get(super.inputCount() + INPUT_Y); - } - - public Value setY(Value n) { - return (Value) inputs().set(super.inputCount() + INPUT_Y, n); - } - - /** - * The opcode of this instruction. - */ - public final int opcode; - - /** - * Creates a new Op2 instance. - * @param kind the result type of this instruction - * @param opcode the bytecode opcode - * @param x the first input instruction - * @param y the second input instruction - */ - public Binary(CiKind kind, int opcode, Value x, Value y, int inputCount, int successorCount, Graph graph) { - super(kind, inputCount + INPUT_COUNT, successorCount + SUCCESSOR_COUNT, graph); - this.opcode = opcode; - setX(x); - setY(y); - } - - /** - * Swaps the operands of this instruction. This is only legal for commutative operations. - */ - public void swapOperands() { - assert Bytecodes.isCommutative(opcode); - Value t = x(); - setX(y()); - setY(t); - } - - @Override - public int valueNumber() { - return Util.hash2(opcode, x(), y()); - } - - @Override - public boolean valueEqual(Node i) { - if (i instanceof Binary) { - Binary o = (Binary) i; - return opcode == o.opcode && x() == o.x() && y() == o.y(); - } - return false; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/BlockClosure.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/BlockClosure.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.ir; - -import com.oracle.max.graal.schedule.*; - -/** - * The {@code BlockClosure} interface represents a closure for iterating over blocks. - */ -public interface BlockClosure { - void apply(Block block); -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/BlockEnd.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/BlockEnd.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,159 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.ir; - -import java.util.*; - -import com.oracle.graal.graph.*; -import com.sun.cri.ci.*; - -/** - * The {@code BlockEnd} instruction is a base class for all instructions that end a basic - * block, including branches, switches, throws, and goto's. - */ -public abstract class BlockEnd extends Instruction { - - private static final int INPUT_COUNT = 0; - - private static final int SUCCESSOR_COUNT = 0; - private final int blockSuccessorCount; - - @Override - protected int inputCount() { - return super.inputCount() + INPUT_COUNT; - } - - @Override - protected int successorCount() { - return super.successorCount() + blockSuccessorCount + SUCCESSOR_COUNT; - } - - /** - * The list of instructions that produce input for this instruction. - */ - public Instruction blockSuccessor(int index) { - assert index >= 0 && index < blockSuccessorCount; - return (Instruction) successors().get(super.successorCount() + SUCCESSOR_COUNT + index); - } - - public Instruction setBlockSuccessor(int index, Instruction n) { - assert index >= 0 && index < blockSuccessorCount; - return (Merge) successors().set(super.successorCount() + SUCCESSOR_COUNT + index, n); - } - - public int blockSuccessorCount() { - return blockSuccessorCount; - } - - /** - * Constructs a new block end with the specified value type. - * @param kind the type of the value produced by this instruction - * @param successors the list of successor blocks. If {@code null}, a new one will be created. - */ - public BlockEnd(CiKind kind, List blockSuccessors, int inputCount, int successorCount, Graph graph) { - this(kind, blockSuccessors.size(), inputCount, successorCount, graph); - for (int i = 0; i < blockSuccessors.size(); i++) { - setBlockSuccessor(i, blockSuccessors.get(i)); - } - } - - public BlockEnd(CiKind kind, int blockSuccessorCount, int inputCount, int successorCount, Graph graph) { - super(kind, inputCount + INPUT_COUNT, successorCount + blockSuccessorCount + SUCCESSOR_COUNT, graph); - this.blockSuccessorCount = blockSuccessorCount; - } - - public BlockEnd(CiKind kind, Graph graph) { - this(kind, 2, 0, 0, graph); - } - - /** - * Gets the block begin associated with this block end. - * @return the beginning of this basic block - */ - public Merge begin() { - for (Node n : predecessors()) { - if (n instanceof Merge) { - return (Merge) n; - } - } - return null; - } - - /** - * Substitutes a successor block in this block end's successor list. Note that - * this method updates all occurrences in the list. - * @param oldSucc the old successor to replace - * @param newSucc the new successor - */ - public int substituteSuccessor(Merge oldSucc, Merge newSucc) { - assert newSucc != null; - int count = 0; - for (int i = 0; i < blockSuccessorCount; i++) { - if (blockSuccessor(i) == oldSucc) { - setBlockSuccessor(i, newSucc); - count++; - } - } - return count; - } - - /** - * Gets the successor corresponding to the default (fall through) case. - * @return the default successor - */ - public Instruction defaultSuccessor() { - return blockSuccessor(blockSuccessorCount - 1); - } - - /** - * Searches for the specified successor and returns its index into the - * successor list if found. - * @param b the block to search for in the successor list - * @return the index of the block in the list if found; -1 otherwise - */ - public int successorIndex(Merge b) { - for (int i = 0; i < blockSuccessorCount; i++) { - if (blockSuccessor(i) == b) { - return i; - } - } - return -1; - } - - /** - * Gets this block end's list of successors. - * @return the successor list - */ - @SuppressWarnings({ "unchecked", "rawtypes"}) - public List blockSuccessors() { - List list = (List) successors().subList(super.successorCount() + SUCCESSOR_COUNT, super.successorCount() + blockSuccessorCount + SUCCESSOR_COUNT); - return Collections.unmodifiableList(list); - } - - public void clearSuccessors() { - for (int i = 0; i < blockSuccessorCount(); i++) { - setBlockSuccessor(i, null); - } - } - -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/BlockList.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/BlockList.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,148 +0,0 @@ -/* - * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.ir; - -import java.util.*; - -/** - * The {@code BlockList} class implements a specialized list data structure for representing - * the predecessor and successor lists of basic blocks. - */ -public class BlockList implements Iterable { - - private Merge[] array; - private int cursor; - - BlockList(int sizeHint) { - if (sizeHint > 0) { - array = new Merge[sizeHint]; - } else { - array = new Merge[2]; - } - } - - public void remove(int index) { - if (index < 0 || index >= cursor) { - throw new IndexOutOfBoundsException(); - } - for (int i = index; i < cursor; i++) { - array[i] = array[i + 1]; - } - cursor--; - } - - public void remove(Merge block) { - int j = 0; - for (int i = 0; i < cursor; i++) { - if (i != j) { - array[j] = array[i]; - } - if (array[i] != block) { - j++; - } - } - cursor = j; - } - - public void exchange(int index1, int index2) { - if (index1 < 0 || index1 >= cursor) { - throw new IndexOutOfBoundsException(); - } - if (index2 < 0 || index2 >= cursor) { - throw new IndexOutOfBoundsException(); - } - Merge t = array[index2]; - array[index2] = array[index1]; - array[index1] = t; - } - - public void insert(int index, Merge block) { - if (index < 0 || index >= cursor) { - throw new IndexOutOfBoundsException(); - } - growOne(); - for (int i = cursor; i > index; i--) { - array[i] = array[i - 1]; - } - array[cursor++] = block; - } - - public void append(Merge block) { - growOne(); - array[cursor++] = block; - } - - public Merge get(int index) { - if (index < 0 || index >= cursor) { - throw new IndexOutOfBoundsException(); - } - return array[index]; - } - - public void replace(Merge oldBlock, Merge newBlock) { - for (int i = 0; i < cursor; i++) { - if (array[i] == oldBlock) { - array[i] = newBlock; - } - } - } - - public boolean checkForSameBlock() { - if (cursor == 0) { - return true; - } - Merge b = array[0]; - for (int i = 1; i < cursor; i++) { - if (array[i] != b) { - return false; - } - } - return true; - } - - public Iterator iterator() { - return new Iter(); - } - - private void growOne() { - if (cursor == array.length) { - array = Arrays.copyOf(array, array.length * 3); - } - } - - private class Iter implements Iterator { - private int pos; - - public boolean hasNext() { - return pos < cursor; - } - - public Merge next() { - return array[pos++]; - } - - public void remove() { - BlockList.this.remove(pos); - } - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/CheckCast.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/CheckCast.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,103 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.ir; - -import com.oracle.graal.graph.*; -import com.sun.c1x.debug.*; -import com.sun.c1x.util.*; -import com.sun.cri.bytecode.*; -import com.sun.cri.ci.*; -import com.sun.cri.ri.*; - -/** - * The {@code CheckCast} instruction represents a {@link Bytecodes#CHECKCAST}. - */ -public final class CheckCast extends TypeCheck { - - private static final int INPUT_COUNT = 0; - private static final int SUCCESSOR_COUNT = 0; - - /** - * Creates a new CheckCast instruction. - * @param targetClass the class being cast to - * @param object the instruction producing the object - * @param stateBefore the state before the cast - * @param graph - */ - public CheckCast(RiType targetClass, Value targetClassInstruction, Value object, Graph graph) { - super(targetClass, targetClassInstruction, object, CiKind.Object, INPUT_COUNT, SUCCESSOR_COUNT, graph); - } - - /** - * Gets the declared type of the result of this instruction. - * @return the declared type of the result - */ - @Override - public RiType declaredType() { - return targetClass; - } - - /** - * Gets the exact type of the result of this instruction. - * @return the exact type of the result - */ - @Override - public RiType exactType() { - return targetClass.isResolved() ? targetClass.exactType() : null; - } - - @Override - public void accept(ValueVisitor v) { - v.visitCheckCast(this); - } - - @Override - public int valueNumber() { - return targetClass.isResolved() ? Util.hash1(Bytecodes.CHECKCAST, object()) : 0; - } - - @Override - public boolean valueEqual(Node i) { - if (i instanceof CheckCast) { - CheckCast o = (CheckCast) i; - return targetClass == o.targetClass && object() == o.object(); - } - return false; - } - - @Override - public void print(LogStream out) { - out.print("checkcast("). - print(object()). - print(","). - print(targetClassInstruction()). - print(") "). - print(CiUtil.toJavaName(targetClass())); - } - - @Override - public Node copy(Graph into) { - CheckCast x = new CheckCast(targetClass, null, null, into); - return x; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/Compare.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/Compare.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,141 +0,0 @@ - -/* - * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.ir; - -import com.oracle.graal.graph.*; -import com.sun.c1x.debug.*; -import com.sun.c1x.util.*; -import com.sun.cri.ci.*; - -public final class Compare extends FloatingNode { - - private static final int INPUT_COUNT = 2; - private static final int INPUT_X = 0; - private static final int INPUT_Y = 1; - - private static final int SUCCESSOR_COUNT = 0; - - @Override - protected int inputCount() { - return super.inputCount() + INPUT_COUNT; - } - - @Override - protected int successorCount() { - return super.successorCount() + SUCCESSOR_COUNT; - } - - /** - * The instruction that produces the first input to this comparison. - */ - public Value x() { - return (Value) inputs().get(super.inputCount() + INPUT_X); - } - - public Value setX(Value n) { - return (Value) inputs().set(super.inputCount() + INPUT_X, n); - } - - /** - * The instruction that produces the second input to this comparison. - */ - public Value y() { - return (Value) inputs().get(super.inputCount() + INPUT_Y); - } - - public Value setY(Value n) { - return (Value) inputs().set(super.inputCount() + INPUT_Y, n); - } - - Condition condition; - boolean unorderedIsTrue; - - /** - * Constructs a new If instruction. - * @param x the instruction producing the first input to the instruction - * @param condition the condition (comparison operation) - * @param y the instruction that produces the second input to this instruction - * @param graph - */ - public Compare(Value x, Condition condition, Value y, Graph graph) { - super(CiKind.Illegal, INPUT_COUNT, SUCCESSOR_COUNT, graph); - assert (x == null && y == null) || Util.archKindsEqual(x, y); - this.condition = condition; - setX(x); - setY(y); - } - - /** - * Gets the condition (comparison operation) for this instruction. - * @return the condition - */ - public Condition condition() { - return condition; - } - - /** - * Checks whether unordered inputs mean true or false. - * @return {@code true} if unordered inputs produce true - */ - public boolean unorderedIsTrue() { - return unorderedIsTrue; - } - - /** - * Swaps the operands to this if and reverses the condition (e.g. > goes to <=). - * @see Condition#mirror() - */ - public void swapOperands() { - condition = condition.mirror(); - Value t = x(); - setX(y()); - setY(t); - } - - @Override - public void accept(ValueVisitor v) { - } - - @Override - public void print(LogStream out) { - out.print("comp "). - print(x()). - print(' '). - print(condition().operator). - print(' '). - print(y()); - } - - @Override - public String shortName() { - return "Comp " + condition.operator; - } - - @Override - public Node copy(Graph into) { - Compare x = new Compare(null, condition, null, into); - x.unorderedIsTrue = unorderedIsTrue; - return x; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/ComputeLinearScanOrder.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/ComputeLinearScanOrder.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,590 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.c1x.ir; - -import java.util.*; - -import com.sun.c1x.*; -import com.sun.c1x.debug.*; -import com.sun.c1x.lir.*; -import com.sun.c1x.util.*; -import com.sun.cri.ci.*; - -public final class ComputeLinearScanOrder { - - private final int maxBlockId; // the highest blockId of a block - private int numBlocks; // total number of blocks (smaller than maxBlockId) - private int numLoops; // total number of loops - private boolean iterativeDominators; // method requires iterative computation of dominators - - List linearScanOrder; // the resulting list of blocks in correct order - - final CiBitMap visitedBlocks; // used for recursive processing of blocks - final CiBitMap activeBlocks; // used for recursive processing of blocks - final CiBitMap dominatorBlocks; // temporary BitMap used for computation of dominator - final int[] forwardBranches; // number of incoming forward branches for each block - final List loopEndBlocks; // list of all loop end blocks collected during countEdges - BitMap2D loopMap; // two-dimensional bit set: a bit is set if a block is contained in a loop - final List workList; // temporary list (used in markLoops and computeOrder) - - // accessors for visitedBlocks and activeBlocks - void initVisited() { - activeBlocks.clearAll(); - visitedBlocks.clearAll(); - } - - boolean isVisited(LIRBlock b) { - return visitedBlocks.get(b.blockID()); - } - - boolean isActive(LIRBlock b) { - return activeBlocks.get(b.blockID()); - } - - void setVisited(LIRBlock b) { - assert !isVisited(b) : "already set"; - visitedBlocks.set(b.blockID()); - } - - void setActive(LIRBlock b) { - assert !isActive(b) : "already set"; - activeBlocks.set(b.blockID()); - } - - void clearActive(LIRBlock b) { - assert isActive(b) : "not already"; - activeBlocks.clear(b.blockID()); - } - - // accessors for forwardBranches - void incForwardBranches(LIRBlock b) { - forwardBranches[b.blockID()]++; - } - - int decForwardBranches(LIRBlock b) { - return --forwardBranches[b.blockID()]; - } - - // accessors for loopMap - boolean isBlockInLoop(int loopIdx, LIRBlock b) { - return loopMap.at(loopIdx, b.blockID()); - } - - void setBlockInLoop(int loopIdx, LIRBlock b) { - loopMap.setBit(loopIdx, b.blockID()); - } - - void clearBlockInLoop(int loopIdx, int blockId) { - loopMap.clearBit(loopIdx, blockId); - } - - // accessors for final result - public List linearScanOrder() { - return linearScanOrder; - } - - public int numLoops() { - return numLoops; - } - - public ComputeLinearScanOrder(int maxBlockId, LIRBlock startBlock) { - - this.maxBlockId = maxBlockId; - visitedBlocks = new CiBitMap(maxBlockId); - activeBlocks = new CiBitMap(maxBlockId); - dominatorBlocks = new CiBitMap(maxBlockId); - forwardBranches = new int[maxBlockId]; - loopEndBlocks = new ArrayList(8); - workList = new ArrayList(8); - - splitCriticalEdges(); - - countEdges(startBlock, null); - - if (numLoops > 0) { - markLoops(); - clearNonNaturalLoops(startBlock); - assignLoopDepth(startBlock); - } - - computeOrder(startBlock); - - printBlocks(); - assert verify(); - } - - void splitCriticalEdges() { - // TODO: move critical edge splitting from IR to here - } - - /** - * Traverses the CFG to analyze block and edge info. The analysis performed is: - * - * 1. Count of total number of blocks. - * 2. Count of all incoming edges and backward incoming edges. - * 3. Number loop header blocks. - * 4. Create a list with all loop end blocks. - */ - void countEdges(LIRBlock cur, LIRBlock parent) { - if (C1XOptions.TraceLinearScanLevel >= 3) { - TTY.println("Counting edges for block B%d%s", cur.blockID(), parent == null ? "" : " coming from B" + parent.blockID()); - } - - if (isActive(cur)) { - if (C1XOptions.TraceLinearScanLevel >= 3) { - TTY.println("backward branch"); - } - assert isVisited(cur) : "block must be visited when block is active"; - assert parent != null : "must have parent"; - - cur.setLinearScanLoopHeader(); - parent.setLinearScanLoopEnd(); - - loopEndBlocks.add(parent); - return; - } - - // increment number of incoming forward branches - incForwardBranches(cur); - - if (isVisited(cur)) { - if (C1XOptions.TraceLinearScanLevel >= 3) { - TTY.println("block already visited"); - } - return; - } - - numBlocks++; - setVisited(cur); - setActive(cur); - - // recursive call for all successors - int i; - for (i = cur.numberOfSux() - 1; i >= 0; i--) { - countEdges(cur.suxAt(i), cur); - } - - clearActive(cur); - - // Each loop has a unique number. - // When multiple loops are nested, assignLoopDepth assumes that the - // innermost loop has the lowest number. This is guaranteed by setting - // the loop number after the recursive calls for the successors above - // have returned. - if (cur.isLinearScanLoopHeader()) { - assert cur.loopIndex() == -1 : "cannot set loop-index twice"; - if (C1XOptions.TraceLinearScanLevel >= 3) { - TTY.println("Block B%d is loop header of loop %d", cur.blockID(), numLoops); - } - - cur.setLoopIndex(numLoops); - numLoops++; - } - - if (C1XOptions.TraceLinearScanLevel >= 3) { - TTY.println("Finished counting edges for block B%d", cur.blockID()); - } - } - - void markLoops() { - if (C1XOptions.TraceLinearScanLevel >= 3) { - TTY.println("----- marking loops"); - } - - loopMap = new BitMap2D(numLoops, maxBlockId); - - for (int i = loopEndBlocks.size() - 1; i >= 0; i--) { - LIRBlock loopEnd = loopEndBlocks.get(i); - LIRBlock loopStart = loopEnd.suxAt(0); - int loopIdx = loopStart.loopIndex(); - - if (C1XOptions.TraceLinearScanLevel >= 3) { - TTY.println("Processing loop from B%d to B%d (loop %d):", loopStart.blockID(), loopEnd.blockID(), loopIdx); - } - assert loopEnd.isLinearScanLoopEnd() : "loop end flag must be set"; -// assert loopEnd.numberOfSux() == 1 : "incorrect number of successors"; - assert loopStart.isLinearScanLoopHeader() : "loop header flag must be set"; - assert loopIdx >= 0 && loopIdx < numLoops : "loop index not set"; - assert workList.isEmpty() : "work list must be empty before processing"; - - // add the end-block of the loop to the working list - workList.add(loopEnd); - setBlockInLoop(loopIdx, loopEnd); - do { - LIRBlock cur = workList.remove(workList.size() - 1); - - if (C1XOptions.TraceLinearScanLevel >= 3) { - TTY.println(" processing B%d", cur.blockID()); - } - assert isBlockInLoop(loopIdx, cur) : "bit in loop map must be set when block is in work list"; - - // recursive processing of all predecessors ends when start block of loop is reached - if (cur != loopStart) { - for (int j = cur.numberOfPreds() - 1; j >= 0; j--) { - LIRBlock pred = cur.predAt(j); - - if (!isBlockInLoop(loopIdx, pred)) { - // this predecessor has not been processed yet, so add it to work list - if (C1XOptions.TraceLinearScanLevel >= 3) { - TTY.println(" pushing B%d", pred.blockID()); - } - workList.add(pred); - setBlockInLoop(loopIdx, pred); - } - } - } - } while (!workList.isEmpty()); - } - } - - // check for non-natural loops (loops where the loop header does not dominate - // all other loop blocks = loops with multiple entries). - // such loops are ignored - void clearNonNaturalLoops(LIRBlock startBlock) { - for (int i = numLoops - 1; i >= 0; i--) { - if (isBlockInLoop(i, startBlock)) { - // loop i contains the entry block of the method. - // this is not a natural loop, so ignore it - if (C1XOptions.TraceLinearScanLevel >= 2) { - TTY.println("Loop %d is non-natural, so it is ignored", i); - } - - for (int blockId = maxBlockId - 1; blockId >= 0; blockId--) { - clearBlockInLoop(i, blockId); - } - iterativeDominators = true; - } - } - } - - void assignLoopDepth(LIRBlock startBlock) { - if (C1XOptions.TraceLinearScanLevel >= 3) { - TTY.println("----- computing loop-depth and weight"); - } - initVisited(); - - assert workList.isEmpty() : "work list must be empty before processing"; - workList.add(startBlock); - - do { - LIRBlock cur = workList.remove(workList.size() - 1); - - if (!isVisited(cur)) { - setVisited(cur); - if (C1XOptions.TraceLinearScanLevel >= 4) { - TTY.println("Computing loop depth for block B%d", cur.blockID()); - } - - // compute loop-depth and loop-index for the block - assert cur.loopDepth() == 0 : "cannot set loop-depth twice"; - int i; - int loopDepth = 0; - int minLoopIdx = -1; - for (i = numLoops - 1; i >= 0; i--) { - if (isBlockInLoop(i, cur)) { - loopDepth++; - minLoopIdx = i; - } - } - cur.setLoopDepth(loopDepth); - cur.setLoopIndex(minLoopIdx); - - // append all unvisited successors to work list - for (i = cur.numberOfSux() - 1; i >= 0; i--) { - workList.add(cur.suxAt(i)); - } - } - } while (!workList.isEmpty()); - } - - int computeWeight(LIRBlock cur) { - LIRBlock singleSux = null; - if (cur.numberOfSux() == 1) { - singleSux = cur.suxAt(0); - } - - // limit loop-depth to 15 bit (only for security reason, it will never be so big) - int weight = (cur.loopDepth() & 0x7FFF) << 16; - - int curBit = 15; - - // this is necessary for the (very rare) case that two successive blocks have - // the same loop depth, but a different loop index (can happen for endless loops - // with exception handlers) - if (!cur.isLinearScanLoopHeader()) { - weight |= 1 << curBit; - } - curBit--; - - // loop end blocks (blocks that end with a backward branch) are added - // after all other blocks of the loop. - if (!cur.isLinearScanLoopEnd()) { - weight |= 1 << curBit; - } - curBit--; - - // critical edge split blocks are preferred because then they have a greater - // probability to be completely empty - //if (cur.isCriticalEdgeSplit()) { - // weight |= 1 << curBit; - //} - //curBit--; - - // exceptions should not be thrown in normal control flow, so these blocks - // are added as late as possible -// if (!(cur.end() instanceof Throw) && (singleSux == null || !(singleSux.end() instanceof Throw))) { -// weight |= 1 << curBit; -// } -// curBit--; -// if (!(cur.end() instanceof Return) && (singleSux == null || !(singleSux.end() instanceof Return))) { -// weight |= 1 << curBit; -// } -// curBit--; - - // exceptions handlers are added as late as possible -// if (!cur.isExceptionEntry()) { -// weight |= 1 << curBit; -// } -// curBit--; - - // guarantee that weight is > 0 - weight |= 1; - - assert curBit >= 0 : "too many flags"; - assert weight > 0 : "weight cannot become negative"; - - return weight; - } - - boolean readyForProcessing(LIRBlock cur) { - // Discount the edge just traveled. - // When the number drops to zero, all forward branches were processed - if (decForwardBranches(cur) != 0) { - return false; - } - - assert !linearScanOrder.contains(cur) : "block already processed (block can be ready only once)"; - assert !workList.contains(cur) : "block already in work-list (block can be ready only once)"; - return true; - } - - void sortIntoWorkList(LIRBlock cur) { - assert !workList.contains(cur) : "block already in work list"; - - int curWeight = computeWeight(cur); - - // the linearScanNumber is used to cache the weight of a block - cur.setLinearScanNumber(curWeight); - - if (C1XOptions.StressLinearScan) { - workList.add(0, cur); - return; - } - - workList.add(null); // provide space for new element - - int insertIdx = workList.size() - 1; - while (insertIdx > 0 && workList.get(insertIdx - 1).linearScanNumber() > curWeight) { - workList.set(insertIdx, workList.get(insertIdx - 1)); - insertIdx--; - } - workList.set(insertIdx, cur); - - if (C1XOptions.TraceLinearScanLevel >= 3) { - TTY.println("Sorted B%d into worklist. new worklist:", cur.blockID()); - for (int i = 0; i < workList.size(); i++) { - TTY.println(String.format("%8d B%02d weight:%6x", i, workList.get(i).blockID(), workList.get(i).linearScanNumber())); - } - } - - for (int i = 0; i < workList.size(); i++) { - assert workList.get(i).linearScanNumber() > 0 : "weight not set"; - assert i == 0 || workList.get(i - 1).linearScanNumber() <= workList.get(i).linearScanNumber() : "incorrect order in worklist"; - } - } - - void appendBlock(LIRBlock cur) { - if (C1XOptions.TraceLinearScanLevel >= 3) { - TTY.println("appending block B%d (weight 0x%06x) to linear-scan order", cur.blockID(), cur.linearScanNumber()); - } - assert !linearScanOrder.contains(cur) : "cannot add the same block twice"; - - // currently, the linear scan order and code emit order are equal. - // therefore the linearScanNumber and the weight of a block must also - // be equal. - cur.setLinearScanNumber(linearScanOrder.size()); - linearScanOrder.add(cur); - } - - void computeOrder(LIRBlock startBlock) { - if (C1XOptions.TraceLinearScanLevel >= 3) { - TTY.println("----- computing final block order"); - } - - // the start block is always the first block in the linear scan order - linearScanOrder = new ArrayList(numBlocks); -// appendBlock(startBlock); - - LIRBlock stdEntry = startBlock; //.suxAt(0); - - // start processing with standard entry block - assert workList.isEmpty() : "list must be empty before processing"; - - if (readyForProcessing(stdEntry)) { - sortIntoWorkList(stdEntry); - } else { - throw new CiBailout("the stdEntry must be ready for processing (otherwise, the method has no start block)"); - } - - do { - LIRBlock cur = workList.remove(workList.size() - 1); - - appendBlock(cur); - - int i; - int numSux = cur.numberOfSux(); - // changed loop order to get "intuitive" order of if- and else-blocks - for (i = 0; i < numSux; i++) { - LIRBlock sux = cur.suxAt(i); - if (readyForProcessing(sux)) { - sortIntoWorkList(sux); - } - } - } while (workList.size() > 0); - } - - public void printBlocks() { - if (C1XOptions.TraceLinearScanLevel >= 2) { - TTY.println("----- loop information:"); - for (LIRBlock cur : linearScanOrder) { - TTY.print(String.format("%4d: B%02d: ", cur.linearScanNumber(), cur.blockID())); - for (int loopIdx = 0; loopIdx < numLoops; loopIdx++) { - TTY.print(String.format("%d = %b ", loopIdx, isBlockInLoop(loopIdx, cur))); - } - TTY.println(String.format(" . loopIndex: %2d, loopDepth: %2d", cur.loopIndex(), cur.loopDepth())); - } - } - - if (C1XOptions.TraceLinearScanLevel >= 1) { - TTY.println("----- linear-scan block order:"); - for (LIRBlock cur : linearScanOrder) { - TTY.print(String.format("%4d: B%02d loop: %2d depth: %2d", cur.linearScanNumber(), cur.blockID(), cur.loopIndex(), cur.loopDepth())); - - TTY.print(cur.isLinearScanLoopHeader() ? " lh" : " "); - TTY.print(cur.isLinearScanLoopEnd() ? " le" : " "); - - TTY.print(" dom: null "); - - - if (cur.numberOfPreds() > 0) { - TTY.print(" preds: "); - for (int j = 0; j < cur.numberOfPreds(); j++) { - LIRBlock pred = cur.predAt(j); - TTY.print("B%d ", pred.blockID()); - } - } - if (cur.numberOfSux() > 0) { - TTY.print(" sux: "); - for (int j = 0; j < cur.numberOfSux(); j++) { - LIRBlock sux = cur.suxAt(j); - TTY.print("B%d ", sux.blockID()); - } - } - TTY.println(); - } - } - } - - boolean verify() { - /* assert linearScanOrder.size() == numBlocks : "wrong number of blocks in list"; - - if (C1XOptions.StressLinearScan) { - // blocks are scrambled when StressLinearScan is used - return true; - } - - // check that all successors of a block have a higher linear-scan-number - // and that all predecessors of a block have a lower linear-scan-number - // (only backward branches of loops are ignored) - int i; - for (i = 0; i < linearScanOrder.size(); i++) { - BlockBegin cur = linearScanOrder.get(i); - - assert cur.linearScanNumber() == i : "incorrect linearScanNumber"; - assert cur.linearScanNumber() >= 0 && cur.linearScanNumber() == linearScanOrder.indexOf(cur) : "incorrect linearScanNumber"; - - for (BlockBegin sux : cur.end().successors()) { - assert sux.linearScanNumber() >= 0 && sux.linearScanNumber() == linearScanOrder.indexOf(sux) : "incorrect linearScanNumber"; - if (!cur.checkBlockFlag(BlockBegin.BlockFlag.LinearScanLoopEnd)) { - assert cur.linearScanNumber() < sux.linearScanNumber() : "invalid order"; - } - if (cur.loopDepth() == sux.loopDepth()) { - assert cur.loopIndex() == sux.loopIndex() || sux.checkBlockFlag(BlockBegin.BlockFlag.LinearScanLoopHeader) : "successing blocks with same loop depth must have same loop index"; - } - } - - for (BlockBegin pred : cur.predecessors()) { - assert pred.linearScanNumber() >= 0 && pred.linearScanNumber() == linearScanOrder.indexOf(pred) : "incorrect linearScanNumber"; - if (!cur.checkBlockFlag(BlockBegin.BlockFlag.LinearScanLoopHeader)) { - assert cur.linearScanNumber() > pred.linearScanNumber() : "invalid order"; - } - if (cur.loopDepth() == pred.loopDepth()) { - assert cur.loopIndex() == pred.loopIndex() || cur.checkBlockFlag(BlockBegin.BlockFlag.LinearScanLoopHeader) : "successing blocks with same loop depth must have same loop index"; - } - - assert cur.dominator().linearScanNumber() <= pred.linearScanNumber() : "dominator must be before predecessors"; - } - - // check dominator - if (i == 0) { - assert cur.dominator() == null : "first block has no dominator"; - } else { - assert cur.dominator() != null : "all but first block must have dominator"; - } - assert cur.numberOfPreds() != 1 || cur.dominator() == cur.predAt(0) || cur.isExceptionEntry() : "Single predecessor must also be dominator"; - } - - // check that all loops are continuous - for (int loopIdx = 0; loopIdx < numLoops; loopIdx++) { - int blockIdx = 0; - assert !isBlockInLoop(loopIdx, linearScanOrder.get(blockIdx)) : "the first block must not be present in any loop"; - - // skip blocks before the loop - while (blockIdx < numBlocks && !isBlockInLoop(loopIdx, linearScanOrder.get(blockIdx))) { - blockIdx++; - } - // skip blocks of loop - while (blockIdx < numBlocks && isBlockInLoop(loopIdx, linearScanOrder.get(blockIdx))) { - blockIdx++; - } - // after the first non-loop block : there must not be another loop-block - while (blockIdx < numBlocks) { - assert !isBlockInLoop(loopIdx, linearScanOrder.get(blockIdx)) : "loop not continuous in linear-scan order"; - blockIdx++; - } - } -*/ - return true; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/Condition.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/Condition.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,206 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.ir; - -import com.sun.cri.bytecode.Bytecodes.*; -import com.sun.cri.ci.*; -import com.sun.cri.ri.*; - -/** - * Condition codes used in conditionals. - */ -public enum Condition { - /** - * Equal. - */ - EQ("=="), - - /** - * Not equal. - */ - NE("!="), - - /** - * Signed less than. - */ - LT("<"), - - /** - * Signed less than or equal. - */ - LE("<="), - - /** - * Signed greater than. - */ - GT(">"), - - /** - * Signed greater than or equal. - */ - GE(">="), - - /** - * Unsigned greater than or equal ("above than or equal"). - */ - AE("|>=|"), - - /** - * Unsigned less than or equal ("below than or equal"). - */ - BE("|<=|"), - - /** - * Unsigned greater than ("above than"). - */ - AT("|>|"), - - /** - * Unsigned less than ("below than"). - */ - BT("|<|"), - - TRUE("TRUE"); - - public final String operator; - - private Condition(String operator) { - this.operator = operator; - } - - public boolean check(int left, int right) { - switch (this) { - case EQ: return left == right; - case NE: return left != right; - case LT: return left < right; - case LE: return left <= right; - case GT: return left > right; - case GE: return left >= right; - case BT: return (left & 0xffffffffL) < (right & 0xffffffffL); - case BE: return (left & 0xffffffffL) <= (right & 0xffffffffL); - case AT: return (left & 0xffffffffL) > (right & 0xffffffffL); - case AE: return (left & 0xffffffffL) >= (right & 0xffffffffL); - } - throw new IllegalArgumentException(); - } - - /** - * Negate this conditional. - * @return the condition that represents the negation - */ - public final Condition negate() { - switch (this) { - case EQ: return NE; - case NE: return EQ; - case LT: return GE; - case LE: return GT; - case GT: return LE; - case GE: return LT; - case BT: return AE; - case BE: return AT; - case AT: return BE; - case AE: return BT; - } - throw new IllegalArgumentException(); - } - - /** - * Mirror this conditional (i.e. commute "a op b" to "b op' a") - * @return the condition representing the equivalent commuted operation - */ - public final Condition mirror() { - switch (this) { - case EQ: return EQ; - case NE: return NE; - case LT: return GT; - case LE: return GE; - case GT: return LT; - case GE: return LE; - case BT: return AT; - case BE: return AE; - case AT: return BT; - case AE: return BE; - } - throw new IllegalArgumentException(); - } - - /** - * Checks if this conditional operation is commutative. - * @return {@code true} if this operation is commutative - */ - public final boolean isCommutative() { - return this == EQ || this == NE; - } - - /** - * Attempts to fold a comparison between two constants and return the result. - * @param lt the constant on the left side of the comparison - * @param rt the constant on the right side of the comparison - * @param runtime the RiRuntime (might be needed to compare runtime-specific types) - * @return {@link Boolean#TRUE} if the comparison is known to be true, - * {@link Boolean#FALSE} if the comparison is known to be false, {@code null} otherwise. - */ - public Boolean foldCondition(CiConstant lt, CiConstant rt, RiRuntime runtime) { - switch (lt.kind) { - case Int: { - int x = lt.asInt(); - int y = rt.asInt(); - switch (this) { - case EQ: return x == y; - case NE: return x != y; - case LT: return x < y; - case LE: return x <= y; - case GT: return x > y; - case GE: return x >= y; - case AE: return UnsignedComparisons.aboveOrEqual(x, y); - case BE: return UnsignedComparisons.belowOrEqual(x, y); - case AT: return UnsignedComparisons.aboveThan(x, y); - case BT: return UnsignedComparisons.belowThan(x, y); - } - break; - } - case Long: { - long x = lt.asLong(); - long y = rt.asLong(); - switch (this) { - case EQ: return x == y; - case NE: return x != y; - case LT: return x < y; - case LE: return x <= y; - case GT: return x > y; - case GE: return x >= y; - } - break; - } - case Object: { - switch (this) { - case EQ: return runtime.areConstantObjectsEqual(lt, rt); - case NE: return !runtime.areConstantObjectsEqual(lt, rt); - } - break; - } - // XXX: folding of floating comparisons should be possible - } - return null; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/Conditional.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/Conditional.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,155 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.ir; - -import com.oracle.graal.graph.*; -import com.sun.c1x.debug.*; -import com.sun.c1x.util.*; -import com.sun.cri.bytecode.*; -import com.sun.cri.ci.*; - -/** - * The {@code IfOp} class represents a comparison that yields one of two values. - * Note that these nodes are not built directly from the bytecode but are introduced - * by conditional expression elimination. - */ -public final class Conditional extends Binary { - - private static final int INPUT_COUNT = 2; - private static final int INPUT_TRUE_VALUE = 0; - private static final int INPUT_FALSE_VALUE = 1; - - private static final int SUCCESSOR_COUNT = 0; - - @Override - protected int inputCount() { - return super.inputCount() + INPUT_COUNT; - } - - @Override - protected int successorCount() { - return super.successorCount() + SUCCESSOR_COUNT; - } - - - /** - * The instruction that produces the value if the comparison is true. - */ - public Value trueValue() { - return (Value) inputs().get(super.inputCount() + INPUT_TRUE_VALUE); - } - - public Value setTrueValue(Value n) { - return (Value) inputs().set(super.inputCount() + INPUT_TRUE_VALUE, n); - } - - /** - * The instruction that produces the value if the comparison is false. - */ - public Value falseValue() { - return (Value) inputs().get(super.inputCount() + INPUT_FALSE_VALUE); - } - - public Value setFalseValue(Value n) { - return (Value) inputs().set(super.inputCount() + INPUT_FALSE_VALUE, n); - } - - - Condition condition; - - /** - * Constructs a new IfOp. - * @param x the instruction producing the first value to be compared - * @param condition the condition of the comparison - * @param y the instruction producing the second value to be compared - * @param trueValue the value produced if the condition is true - * @param falseValue the value produced if the condition is false - */ - public Conditional(Value x, Condition condition, Value y, Value trueValue, Value falseValue, Graph graph) { - // TODO: return the appropriate bytecode IF_ICMPEQ, etc - super(trueValue.kind.meet(falseValue.kind), Bytecodes.ILLEGAL, x, y, INPUT_COUNT, SUCCESSOR_COUNT, graph); - this.condition = condition; - setTrueValue(trueValue); - setFalseValue(falseValue); - } - - // for copying - private Conditional(CiKind kind, Condition cond, Graph graph) { - super(kind, Bytecodes.ILLEGAL, null, null, INPUT_COUNT, SUCCESSOR_COUNT, graph); - this.condition = cond; - } - - /** - * Gets the condition of this if operation. - * @return the condition - */ - public Condition condition() { - return condition; - } - - /** - * Checks whether this comparison operator is commutative (i.e. it is either == or !=). - * @return {@code true} if this comparison is commutative - */ - public boolean isCommutative() { - return condition == Condition.EQ || condition == Condition.NE; - } - - @Override - public void accept(ValueVisitor v) { - v.visitIfOp(this); - } - - @Override - public int valueNumber() { - return Util.hash4(condition.hashCode(), x(), y(), trueValue(), falseValue()); - } - - @Override - public boolean valueEqual(Node i) { - if (i instanceof Conditional) { - Conditional o = (Conditional) i; - return opcode == o.opcode && x() == o.x() && y() == o.y() && trueValue() == o.trueValue() && falseValue() == o.falseValue(); - } - return false; - } - - @Override - public void print(LogStream out) { - out.print(x()). - print(' '). - print(condition().operator). - print(' '). - print(y()). - print(" ? "). - print(trueValue()). - print(" : "). - print(falseValue()); - } - - @Override - public Node copy(Graph into) { - Conditional x = new Conditional(kind, condition, into); - return x; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/Constant.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/Constant.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,199 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.ir; - -import static com.sun.c1x.C1XCompilation.*; - -import com.oracle.graal.graph.*; -import com.sun.c1x.debug.*; -import com.sun.cri.ci.*; -import com.sun.cri.ri.*; - -/** - * The {@code Constant} instruction represents a constant such as an integer value, - * long, float, object reference, address, etc. - */ -public final class Constant extends FloatingNode { - - private static final int INPUT_COUNT = 0; - private static final int SUCCESSOR_COUNT = 0; - - public final CiConstant value; - - /** - * Constructs a new instruction representing the specified constant. - * @param value the constant - * @param graph - */ - public Constant(CiConstant value, Graph graph) { - super(value.kind.stackKind(), INPUT_COUNT, SUCCESSOR_COUNT, graph); - this.value = value; - } - - @Override - public void accept(ValueVisitor v) { - v.visitConstant(this); - } - - /** - * Creates an instruction for a double constant. - * @param d the double value for which to create the instruction - * @param graph - * @return an instruction representing the double - */ - public static Constant forDouble(double d, Graph graph) { - return new Constant(CiConstant.forDouble(d), graph); - } - - /** - * Creates an instruction for a float constant. - * @param f the float value for which to create the instruction - * @return an instruction representing the float - */ - public static Constant forFloat(float f, Graph graph) { - return new Constant(CiConstant.forFloat(f), graph); - } - - /** - * Creates an instruction for an long constant. - * @param i the long value for which to create the instruction - * @return an instruction representing the long - */ - public static Constant forLong(long i, Graph graph) { - return new Constant(CiConstant.forLong(i), graph); - } - - /** - * Creates an instruction for an integer constant. - * @param i the integer value for which to create the instruction - * @return an instruction representing the integer - */ - public static Constant forInt(int i, Graph graph) { - return new Constant(CiConstant.forInt(i), graph); - } - - /** - * Creates an instruction for a boolean constant. - * @param i the boolean value for which to create the instruction - * @return an instruction representing the boolean - */ - public static Constant forBoolean(boolean i, Graph graph) { - return new Constant(CiConstant.forBoolean(i), graph); - } - - /** - * Creates an instruction for an address (jsr/ret address) constant. - * @param i the address value for which to create the instruction - * @return an instruction representing the address - */ - public static Constant forJsr(int i, Graph graph) { - return new Constant(CiConstant.forJsr(i), graph); - } - - /** - * Creates an instruction for an object constant. - * @param o the object value for which to create the instruction - * @return an instruction representing the object - */ - public static Constant forObject(Object o, Graph graph) { - return new Constant(CiConstant.forObject(o), graph); - } - - /** - * Creates an instruction for a word constant. - * @param val the word value for which to create the instruction - * @return an instruction representing the word - */ - public static Constant forWord(long val, Graph graph) { - return new Constant(CiConstant.forWord(val), graph); - } - - public static Constant defaultForKind(CiKind kind, Graph graph) { - switch(kind) { - case Boolean: - return Constant.forBoolean(false, graph); - case Byte: - case Char: - case Short: - case Int: - return Constant.forInt(0, graph); - case Double: - return Constant.forDouble(0.0, graph); - case Float: - return Constant.forFloat(0.0f, graph); - case Long: - return Constant.forLong(0L, graph); - case Object: - return Constant.forObject(null, graph); - case Word: - return Constant.forWord(0L, graph); - default: - return null; - } - } - - @Override - public String toString() { - return super.toString() + "(" + value + ")"; - } - - @Override - public int valueNumber() { - return 0x50000000 | value.hashCode(); - } - - @Override - public boolean valueEqual(Node i) { - return i instanceof Constant && ((Constant) i).value.equivalent(this.value); - } - - @Override - public RiType declaredType() { - RiRuntime runtime = compilation().runtime; - if (kind.isPrimitive()) { - runtime.asRiType(kind); - } - return runtime.getTypeOf(asConstant()); - } - - @Override - public RiType exactType() { - return declaredType(); - } - - @Override - public void print(LogStream out) { - out.print(value.valueString()); - } - - @Override - public String shortName() { - return value.name(); - } - - @Override - public Node copy(Graph into) { - Constant x = new Constant(value, into); - return x; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/Convert.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/Convert.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,109 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.ir; - -import com.oracle.graal.graph.*; -import com.sun.c1x.debug.*; -import com.sun.c1x.util.*; -import com.sun.cri.bytecode.*; -import com.sun.cri.ci.*; - -/** - * The {@code Convert} class represents a conversion between primitive types. - */ -public final class Convert extends FloatingNode { - - private static final int INPUT_COUNT = 1; - private static final int INPUT_VALUE = 0; - - private static final int SUCCESSOR_COUNT = 0; - - @Override - protected int inputCount() { - return super.inputCount() + INPUT_COUNT; - } - - @Override - protected int successorCount() { - return super.successorCount() + SUCCESSOR_COUNT; - } - - /** - * The instruction which produces the input value to this instruction. - */ - public Value value() { - return (Value) inputs().get(super.inputCount() + INPUT_VALUE); - } - - public Value setValue(Value n) { - return (Value) inputs().set(super.inputCount() + INPUT_VALUE, n); - } - - /** - * The opcode for this conversion operation. - */ - public final int opcode; - - /** - * Constructs a new Convert instance. - * @param opcode the bytecode representing the operation - * @param value the instruction producing the input value - * @param kind the result type of this instruction - * @param graph - */ - public Convert(int opcode, Value value, CiKind kind, Graph graph) { - super(kind, INPUT_COUNT, SUCCESSOR_COUNT, graph); - this.opcode = opcode; - setValue(value); - } - - @Override - public void accept(ValueVisitor v) { - v.visitConvert(this); - } - - @Override - public int valueNumber() { - return Util.hash1(opcode, value()); - } - - @Override - public boolean valueEqual(Node i) { - if (i instanceof Convert) { - Convert o = (Convert) i; - return opcode == o.opcode && value() == o.value(); - } - return false; - } - - @Override - public void print(LogStream out) { - out.print(Bytecodes.nameOf(opcode)).print('(').print(value()).print(')'); - } - - @Override - public Node copy(Graph into) { - Convert x = new Convert(opcode, null, kind, into); - return x; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/Deoptimize.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/Deoptimize.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.ir; - -import com.oracle.graal.graph.*; -import com.sun.c1x.debug.*; -import com.sun.cri.ci.*; - -public class Deoptimize extends Instruction { - - private static final int INPUT_COUNT = 0; - private static final int SUCCESSOR_COUNT = 0; - - private String message; - - public Deoptimize(Graph graph) { - super(CiKind.Illegal, INPUT_COUNT, SUCCESSOR_COUNT, graph); - } - - public void setMessage(String message) { - this.message = message; - } - - public String message() { - return message; - } - - @Override - public void accept(ValueVisitor v) { - v.visitDeoptimize(this); - } - - @Override - public void print(LogStream out) { - out.print("deoptimize"); - } - - @Override - public String shortName() { - return message == null ? "Deopt " : "Deopt " + message; - } - - @Override - public Node copy(Graph into) { - Deoptimize x = new Deoptimize(into); - x.setMessage(message); - return x; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/ExceptionDispatch.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/ExceptionDispatch.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,133 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.ir; - -import com.oracle.graal.graph.*; -import com.sun.c1x.debug.*; -import com.sun.cri.ci.*; -import com.sun.cri.ri.*; - -/** - * This instruction takes an exception object and has two successors: - * The catchSuccessor is called whenever the exception matches the given type, otherwise otherSuccessor is called. - */ -public final class ExceptionDispatch extends BlockEnd { - - private static final int INPUT_COUNT = 1; - private static final int INPUT_EXCEPTION = 0; - - private static final int SUCCESSOR_COUNT = 0; - - @Override - protected int inputCount() { - return super.inputCount() + INPUT_COUNT; - } - - @Override - protected int successorCount() { - return super.successorCount() + SUCCESSOR_COUNT; - } - - /** - * The instruction producing the exception object. - */ - public Value exception() { - return (Value) inputs().get(super.inputCount() + INPUT_EXCEPTION); - } - - public Value setException(Value n) { - return (Value) inputs().set(super.inputCount() + INPUT_EXCEPTION, n); - } - - private final RiType catchType; - - /** - * Constructs a new ExceptionDispatch instruction. - */ - public ExceptionDispatch(Value exception, Instruction catchSuccessor, Instruction otherSuccessor, RiType catchType, Graph graph) { - super(CiKind.Int, 2, INPUT_COUNT, SUCCESSOR_COUNT, graph); - setException(exception); - setBlockSuccessor(0, otherSuccessor); - setBlockSuccessor(1, catchSuccessor); - this.catchType = catchType; - } - - public RiType catchType() { - return catchType; - } - - /** - * Gets the block corresponding to the catch block. - * @return the true successor - */ - public Instruction catchSuccessor() { - return blockSuccessor(1); - } - - /** - * Gets the block corresponding to the rest of the dispatch chain. - * @return the false successor - */ - public Instruction otherSuccessor() { - return blockSuccessor(0); - } - - /** - * Gets the block corresponding to the specified outcome of the branch. - * @param istrue {@code true} if the true successor is requested, {@code false} otherwise - * @return the corresponding successor - */ - public Instruction successor(boolean istrue) { - return blockSuccessor(istrue ? 1 : 0); - } - - @Override - public void accept(ValueVisitor v) { - v.visitExceptionDispatch(this); - } - - @Override - public void print(LogStream out) { - out.print("exception_dispatch "). - print(exception()). - print(' '). - print("instanceof"). - print(' '). - print(catchType().name()). - print(" then "). - print(blockSuccessors().get(1).toString()). - print(" else B"). - print(blockSuccessors().get(0).toString()); - } - - @Override - public String shortName() { - return "Dispatch " + catchType().name(); - } - - @Override - public Node copy(Graph into) { - ExceptionDispatch x = new ExceptionDispatch(null, null, null, catchType, into); - return x; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/ExceptionEdgeInstruction.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/ExceptionEdgeInstruction.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.ir; - - -public interface ExceptionEdgeInstruction { - Instruction exceptionEdge(); -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/ExceptionObject.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/ExceptionObject.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.ir; - -import com.oracle.graal.graph.*; -import com.sun.c1x.debug.*; -import com.sun.cri.ci.*; - -/** - * The {@code ExceptionObject} instruction represents the incoming exception object to an exception handler. - */ -public final class ExceptionObject extends Instruction { - - private static final int INPUT_COUNT = 0; - private static final int SUCCESSOR_COUNT = 0; - - /** - * Constructs a new ExceptionObject instruction. - * @param stateBefore TODO - * @param graph - */ - public ExceptionObject(Graph graph) { - super(CiKind.Object, INPUT_COUNT, SUCCESSOR_COUNT, graph); - } - - @Override - public void accept(ValueVisitor v) { - v.visitExceptionObject(this); - } - - @Override - public void print(LogStream out) { - out.print("incoming exception"); - } - - @Override - public Node copy(Graph into) { - ExceptionObject x = new ExceptionObject(into); - return x; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/FixedNode.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/FixedNode.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.ir; - -import com.oracle.graal.graph.*; -import com.sun.cri.ci.*; - - -public abstract class FixedNode extends Value { - - public FixedNode(CiKind kind, int inputCount, int successorCount, Graph graph) { - super(kind, inputCount, successorCount, graph); - } - -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/FloatingNode.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/FloatingNode.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.ir; - -import com.oracle.graal.graph.*; -import com.sun.cri.ci.*; - - -public abstract class FloatingNode extends Value { - - /** - * @param kind - * @param inputCount - * @param successorCount - * @param graph - */ - public FloatingNode(CiKind kind, int inputCount, int successorCount, Graph graph) { - super(kind, inputCount, successorCount, graph); - } - -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/If.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/If.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,119 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.ir; - -import com.oracle.graal.graph.*; -import com.sun.c1x.debug.*; -import com.sun.cri.ci.*; - -/** - * The {@code If} instruction represents a branch that can go one of two directions - * depending on the outcome of a comparison. - */ -public final class If extends BlockEnd { - - private static final int INPUT_COUNT = 1; - private static final int INPUT_COMPARE = 0; - - private static final int SUCCESSOR_COUNT = 0; - - @Override - protected int inputCount() { - return super.inputCount() + INPUT_COUNT; - } - - @Override - protected int successorCount() { - return super.successorCount() + SUCCESSOR_COUNT; - } - - /** - * The instruction that produces the first input to this comparison. - */ - public Compare compare() { - return (Compare) inputs().get(super.inputCount() + INPUT_COMPARE); - } - - public Value setCompare(Compare n) { - return (Value) inputs().set(super.inputCount() + INPUT_COMPARE, n); - } - - public If(Compare compare, Graph graph) { - super(CiKind.Illegal, 2, INPUT_COUNT, SUCCESSOR_COUNT, graph); - setCompare(compare); - } - - /** - * Gets the block corresponding to the true successor. - * @return the true successor - */ - public Instruction trueSuccessor() { - return blockSuccessor(0); - } - - /** - * Gets the block corresponding to the false successor. - * @return the false successor - */ - public Instruction falseSuccessor() { - return blockSuccessor(1); - } - - /** - * Gets the block corresponding to the specified outcome of the branch. - * @param istrue {@code true} if the true successor is requested, {@code false} otherwise - * @return the corresponding successor - */ - public Instruction successor(boolean istrue) { - return blockSuccessor(istrue ? 0 : 1); - } - - @Override - public void accept(ValueVisitor v) { - v.visitIf(this); - } - - @Override - public void print(LogStream out) { - out.print("if "). - print(compare().x()). - print(' '). - print(compare().condition().operator). - print(' '). - print(compare().y()). - print(" then "). - print(blockSuccessors().get(0)). - print(" else "). - print(blockSuccessors().get(1)); - } - - @Override - public String shortName() { - return "If " + compare().condition.operator; - } - - @Override - public Node copy(Graph into) { - return new If(compare(), into); - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/InstanceOf.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/InstanceOf.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.ir; - -import com.oracle.graal.graph.*; -import com.sun.c1x.debug.*; -import com.sun.c1x.util.*; -import com.sun.cri.bytecode.*; -import com.sun.cri.ci.*; -import com.sun.cri.ri.*; - -/** - * The {@code InstanceOf} instruction represents an instanceof test. - */ -public final class InstanceOf extends TypeCheck { - - private static final int INPUT_COUNT = 0; - private static final int SUCCESSOR_COUNT = 0; - - /** - * Constructs a new InstanceOf instruction. - * @param targetClass the target class of the instanceof check - * @param object the instruction producing the object input to this instruction - * @param graph - */ - public InstanceOf(RiType targetClass, Value targetClassInstruction, Value object, Graph graph) { - super(targetClass, targetClassInstruction, object, CiKind.Int, INPUT_COUNT, SUCCESSOR_COUNT, graph); - } - - @Override - public void accept(ValueVisitor v) { - v.visitInstanceOf(this); - } - - @Override - public int valueNumber() { - return Util.hash1(Bytecodes.INSTANCEOF, object()); - } - - @Override - public boolean valueEqual(Node i) { - if (i instanceof InstanceOf) { - InstanceOf o = (InstanceOf) i; - return targetClass == o.targetClass && object() == o.object(); - } - return false; - } - - @Override - public void print(LogStream out) { - out.print("instanceof(").print(object()).print(") ").print(CiUtil.toJavaName(targetClass())); - } - - @Override - public Node copy(Graph into) { - InstanceOf x = new InstanceOf(targetClass, null, null, into); - return x; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/Instruction.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/Instruction.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,120 +0,0 @@ -/* - * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.ir; - -import java.util.*; - -import com.oracle.graal.graph.*; -import com.sun.c1x.*; -import com.sun.c1x.value.*; -import com.sun.cri.ci.*; - -/** - * Denotes an instruction node in the IR, which is a {@link Value} that - * can be added to a basic block (whereas other {@link Value} nodes such as {@link Phi} and - * {@link Local} cannot be added to basic blocks). - * - * Subclasses of instruction represent arithmetic and object operations, - * control flow operators, phi statements, method calls, the start of basic blocks, and - * the end of basic blocks. - * - * Instruction nodes are chained together in a basic block through the embedded - * {@link Instruction#next} field. An Instruction may also have a list of {@link ExceptionHandler}s. - */ -public abstract class Instruction extends FixedNode { - - private static final int INPUT_COUNT = 0; - - private static final int SUCCESSOR_COUNT = 1; - public static final int SUCCESSOR_NEXT = 0; - - @Override - protected int inputCount() { - return super.inputCount() + INPUT_COUNT; - } - - @Override - protected int successorCount() { - return super.successorCount() + SUCCESSOR_COUNT; - } - - /** - * Links to next instruction in a basic block, to {@code null} if this instruction is the end of a basic block or to - * itself if not in a block. - */ - public Instruction next() { - return (Instruction) successors().get(super.successorCount() + SUCCESSOR_NEXT); - } - - public Node setNext(Instruction next) { - return successors().set(super.successorCount() + SUCCESSOR_NEXT, next); - } - - public int nextIndex() { - return super.successorCount() + SUCCESSOR_NEXT; - } - - - public static final int SYNCHRONIZATION_ENTRY_BCI = -1; - - /** - * Constructs a new instruction with the specified value type. - * @param kind the value type for this instruction - * @param inputCount - * @param successorCount - */ - public Instruction(CiKind kind, int inputCount, int successorCount, Graph graph) { - super(kind, inputCount + INPUT_COUNT, successorCount + SUCCESSOR_COUNT, graph); - C1XMetrics.HIRInstructions++; - } - - - /** - * Gets the list of predecessors of this block. - * @return the predecessor list - */ - @SuppressWarnings({ "unchecked", "rawtypes" }) - public List blockPredecessors() { - return (List) Collections.unmodifiableList(predecessors()); - } - - /** - * Get the number of predecessors. - * @return the number of predecessors - */ - public int numberOfPreds() { - return predecessors().size(); - } - - public Instruction predAt(int j) { - return (Instruction) predecessors().get(j); - } - - /** - * Gets the state after the instruction, if it is recorded. - * @return the state after the instruction - */ - public FrameState stateAfter() { - return null; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/Invoke.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/Invoke.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,202 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.ir; - -import java.util.*; - -import com.oracle.graal.graph.*; -import com.sun.c1x.debug.*; -import com.sun.c1x.util.*; -import com.sun.cri.bytecode.*; -import com.sun.cri.ci.*; -import com.sun.cri.ri.*; - -/** - * The {@code Invoke} instruction represents all kinds of method calls. - */ -public final class Invoke extends StateSplit implements ExceptionEdgeInstruction { - - private final int argumentCount; - - private static final int SUCCESSOR_COUNT = 1; - private static final int SUCCESSOR_EXCEPTION_EDGE = 0; - - @Override - protected int inputCount() { - return super.inputCount() + argumentCount; - } - - @Override - protected int successorCount() { - return super.successorCount() + SUCCESSOR_COUNT; - } - - /** - * The list of instructions that produce input for this instruction. - */ - public Value argument(int index) { - assert index >= 0 && index < argumentCount; - return (Value) inputs().get(super.inputCount() + index); - } - - public Value setArgument(int index, Value n) { - assert index >= 0 && index < argumentCount; - return (Value) inputs().set(super.inputCount() + index, n); - } - - public int argumentCount() { - return argumentCount; - } - - /** - * The entry to the exception dispatch chain for this invoke. - */ - @Override - public Instruction exceptionEdge() { - return (Instruction) successors().get(super.successorCount() + SUCCESSOR_EXCEPTION_EDGE); - } - - public Instruction setExceptionEdge(Instruction n) { - return (Instruction) successors().set(super.successorCount() + SUCCESSOR_EXCEPTION_EDGE, n); - } - - public final int opcode; - public final RiMethod target; - public final RiType returnType; - public final int bci; // XXX needed because we can not compute the bci from the sateBefore bci of this Invoke was optimized from INVOKEINTERFACE to INVOKESPECIAL - - /** - * Constructs a new Invoke instruction. - * - * @param opcode the opcode of the invoke - * @param result the result type - * @param args the list of instructions producing arguments to the invocation, including the receiver object - * @param isStatic {@code true} if this call is static (no receiver object) - * @param target the target method being called - * @param stateBefore the state before executing the invocation - */ - public Invoke(int bci, int opcode, CiKind result, Value[] args, RiMethod target, RiType returnType, Graph graph) { - super(result, args.length, SUCCESSOR_COUNT, graph); - this.opcode = opcode; - this.target = target; - this.returnType = returnType; - this.bci = bci; - - this.argumentCount = args.length; - for (int i = 0; i < args.length; i++) { - setArgument(i, args[i]); - } - } - - /** - * Gets the opcode of this invoke instruction. - * @return the opcode - */ - public int opcode() { - return opcode; - } - - /** - * Checks whether this is an invocation of a static method. - * @return {@code true} if the invocation is a static invocation - */ - public boolean isStatic() { - return opcode == Bytecodes.INVOKESTATIC; - } - - @Override - public RiType declaredType() { - return returnType; - } - - /** - * Gets the instruction that produces the receiver object for this invocation, if any. - * @return the instruction that produces the receiver object for this invocation if any, {@code null} if this - * invocation does not take a receiver object - */ - public Value receiver() { - assert !isStatic(); - return argument(0); - } - - /** - * Gets the target method for this invocation instruction. - * @return the target method - */ - public RiMethod target() { - return target; - } - - /** - * Checks whether this invocation has a receiver object. - * @return {@code true} if this invocation has a receiver object; {@code false} otherwise, if this is a - * static call - */ - public boolean hasReceiver() { - return !isStatic(); - } - - @Override - public void accept(ValueVisitor v) { - v.visitInvoke(this); - } - - public CiKind[] signature() { - CiKind receiver = isStatic() ? null : target.holder().kind(); - return Util.signatureToKinds(target.signature(), receiver); - } - - @Override - public void print(LogStream out) { - int argStart = 0; - if (hasReceiver()) { - out.print(receiver()).print('.'); - argStart = 1; - } - - RiMethod target = target(); - out.print(target.name()).print('('); - for (int i = argStart; i < argumentCount; i++) { - if (i > argStart) { - out.print(", "); - } - out.print(argument(i)); - } - out.print(CiUtil.format(") [method: %H.%n(%p):%r]", target, false)); - } - - @Override - public Map getDebugProperties() { - Map properties = super.getDebugProperties(); - properties.put("opcode", Bytecodes.nameOf(opcode)); - properties.put("target", CiUtil.format("%H.%n(%p):%r", target, false)); - properties.put("bci", bci); - return properties; - } - - @Override - public Node copy(Graph into) { - Invoke x = new Invoke(bci, opcode, kind, new Value[argumentCount], target, returnType, into); - return x; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/LeftShift.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/LeftShift.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.ir; - -import com.oracle.graal.graph.*; -import com.sun.cri.bytecode.*; -import com.sun.cri.ci.*; - - -public final class LeftShift extends Shift { - - /** - * @param opcode - * @param kind - * @param x - * @param y - * @param graph - */ - public LeftShift(CiKind kind, Value x, Value y, Graph graph) { - super(kind, kind == CiKind.Int ? Bytecodes.ISHL : Bytecodes.LSHL, x, y, graph); - } - - @Override - public String shortName() { - return "<<"; - } - - @Override - public Node copy(Graph into) { - LeftShift ls = new LeftShift(kind, null, null, graph()); - return ls; - } - -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/LoadField.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/LoadField.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,97 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.ir; - -import com.oracle.graal.graph.*; -import com.sun.c1x.debug.*; -import com.sun.cri.ci.*; -import com.sun.cri.ri.*; - -/** - * The {@code LoadField} instruction represents a read of a static or instance field. - */ -public final class LoadField extends AccessField { - - private static final int INPUT_COUNT = 0; - private static final int SUCCESSOR_COUNT = 0; - - /** - * Creates a new LoadField instance. - * @param object the receiver object - * @param field the compiler interface field - * @param isStatic indicates if the field is static - * @param stateAfter the state after the field access - * @param graph - * @param isLoaded indicates if the class is loaded - */ - public LoadField(Value object, RiField field, Graph graph) { - super(field.kind().stackKind(), object, field, INPUT_COUNT, SUCCESSOR_COUNT, graph); - } - - /** - * Gets the declared type of the field being accessed. - * @return the declared type of the field being accessed. - */ - @Override - public RiType declaredType() { - return field().type(); - } - - /** - * Gets the exact type of the field being accessed. If the field type is - * a primitive array or an instance class and the class is loaded and final, - * then the exact type is the same as the declared type. Otherwise it is {@code null} - * @return the exact type of the field if known; {@code null} otherwise - */ - @Override - public RiType exactType() { - RiType declaredType = declaredType(); - return declaredType.isResolved() ? declaredType.exactType() : null; - } - - @Override - public void accept(ValueVisitor v) { - v.visitLoadField(this); - } - - @Override - public void print(LogStream out) { - out.print(object()). - print("."). - print(field.name()). - print(" [field: "). - print(CiUtil.format("%h.%n:%t", field, false)). - print("]"); - } - - @Override - public boolean needsStateAfter() { - return false; - } - - @Override - public Node copy(Graph into) { - LoadField x = new LoadField(null, field, into); - return x; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/LoadIndexed.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/LoadIndexed.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,93 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.ir; - -import com.oracle.graal.graph.*; -import com.sun.c1x.debug.*; -import com.sun.cri.ci.*; -import com.sun.cri.ri.*; - -/** - * The {@code LoadIndexed} instruction represents a read from an element of an array. - */ -public final class LoadIndexed extends AccessIndexed { - - private static final int INPUT_COUNT = 0; - private static final int SUCCESSOR_COUNT = 0; - - /** - * Creates a new LoadIndexed instruction. - * @param array the instruction producing the array - * @param index the instruction producing the index - * @param length the instruction producing the length - * @param elementKind the element type - * @param graph - */ - public LoadIndexed(Value array, Value index, Value length, CiKind elementKind, Graph graph) { - super(elementKind.stackKind(), array, index, length, elementKind, INPUT_COUNT, SUCCESSOR_COUNT, graph); - } - - /** - * Gets the declared type of this instruction's result. - * @return the declared type - */ - @Override - public RiType declaredType() { - RiType arrayType = array().declaredType(); - if (arrayType == null) { - return null; - } - return arrayType.componentType(); - } - - /** - * Gets the exact type of this instruction's result. - * @return the exact type - */ - @Override - public RiType exactType() { - RiType declared = declaredType(); - return declared != null && declared.isResolved() ? declared.exactType() : null; - } - - @Override - public void accept(ValueVisitor v) { - v.visitLoadIndexed(this); - } - - @Override - public void print(LogStream out) { - out.print(array()).print('[').print(index()).print("] (").print(kind.typeChar).print(')'); - } - - @Override - public boolean needsStateAfter() { - return false; - } - - @Override - public Node copy(Graph into) { - LoadIndexed x = new LoadIndexed(null, null, null, elementKind(), into); - return x; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/Local.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/Local.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,99 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.ir; - -import com.oracle.graal.graph.*; -import com.sun.c1x.debug.*; -import com.sun.cri.ci.*; -import com.sun.cri.ri.*; - -/** - * The {@code Local} instruction is a placeholder for an incoming argument - * to a function call. - */ -public final class Local extends FloatingNode { - - private static final int INPUT_COUNT = 1; - - private static final int SUCCESSOR_COUNT = 0; - - private final int index; - private RiType declaredType; - - public Local(CiKind kind, int javaIndex, Graph graph) { - super(kind, INPUT_COUNT, SUCCESSOR_COUNT, graph); - this.index = javaIndex; - } - - /** - * Gets the index of this local. - * @return the index - */ - public int index() { - return index; - } - - /** - * Sets the declared type of this local, e.g. derived from the signature of the method. - * @param declaredType the declared type of the local variable - */ - public void setDeclaredType(RiType declaredType) { - this.declaredType = declaredType; - } - - /** - * Computes the declared type of the result of this instruction, if possible. - * @return the declared type of the result of this instruction, if it is known; {@code null} otherwise - */ - @Override - public RiType declaredType() { - return declaredType; - } - - @Override - public void accept(ValueVisitor v) { - v.visitLocal(this); - } - - @Override - public void print(LogStream out) { - out.print("local[index ").print(index()).print(']'); - } - - @Override - protected int inputCount() { - return super.inputCount() + INPUT_COUNT; - } - - @Override - protected int successorCount() { - return super.successorCount() + SUCCESSOR_COUNT; - } - - @Override - public Node copy(Graph into) { - Local x = new Local(kind, index, into); - x.setDeclaredType(declaredType()); - return x; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/Logic.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/Logic.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.ir; - -import com.oracle.graal.graph.*; -import com.sun.c1x.debug.*; -import com.sun.cri.ci.*; - -/** - * The {@code LogicOp} class definition. - */ -public abstract class Logic extends Binary { - - private static final int INPUT_COUNT = 0; - private static final int SUCCESSOR_COUNT = 0; - - /** - * Constructs a new logic operation instruction. - * @param opcode the opcode of the logic operation - * @param x the first input into this instruction - * @param y the second input into this instruction - */ - public Logic(CiKind kind, int opcode, Value x, Value y, Graph graph) { - super(kind, opcode, x, y, INPUT_COUNT, SUCCESSOR_COUNT, graph); - } - - @Override - public void accept(ValueVisitor v) { - v.visitLogic(this); - } - - @Override - public void print(LogStream out) { - out.print(x()).print(' ').print(this.shortName()).print(' ').print(y()); - } - - @Override - public abstract String shortName(); -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/LookupSwitch.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/LookupSwitch.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,92 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.ir; - -import static com.sun.c1x.debug.InstructionPrinter.InstructionLineColumn.*; - -import java.util.*; - -import com.oracle.graal.graph.*; -import com.sun.c1x.debug.*; - -/** - * The {@code LookupSwitch} instruction represents a lookup switch bytecode, which has a sorted - * array of key values. - */ -public final class LookupSwitch extends Switch { - - private static final int INPUT_COUNT = 0; - private static final int SUCCESSOR_COUNT = 0; - - final int[] keys; - - /** - * Constructs a new LookupSwitch instruction. - * @param value the instruction producing the value being switched on - * @param successors the list of successors - * @param keys the list of keys, sorted - * @param stateAfter the state after the switch - * @param graph - */ - public LookupSwitch(Value value, List successors, int[] keys, Graph graph) { - super(value, successors, INPUT_COUNT, SUCCESSOR_COUNT, graph); - this.keys = keys; - } - - /** - * Gets the key at the specified index. - * @param i the index - * @return the key at that index - */ - public int keyAt(int i) { - return keys[i]; - } - - public int keysLength() { - return keys.length; - } - - @Override - public void accept(ValueVisitor v) { - v.visitLookupSwitch(this); - } - - @Override - public void print(LogStream out) { - out.print("lookupswitch "); - out.println(value()); - int l = numberOfCases(); - for (int i = 0; i < l; i++) { - INSTRUCTION.advance(out); - out.printf("case %5d: B%d%n", keyAt(i), blockSuccessors().get(i)); - } - INSTRUCTION.advance(out); - out.print("default : ").print(defaultSuccessor()); - } - - @Override - public Node copy(Graph into) { - LookupSwitch x = new LookupSwitch(null, Arrays.asList(new Instruction[numberOfCases() + 1]), keys.clone(), into); - return x; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/LoopBegin.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/LoopBegin.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.ir; - -import com.oracle.graal.graph.*; -import com.sun.c1x.debug.*; - -public class LoopBegin extends Merge { - - private static final int INPUT_COUNT = 0; - private static final int SUCCESSOR_COUNT = 0; - - public LoopBegin(Graph graph) { - super(INPUT_COUNT, SUCCESSOR_COUNT, graph); - } - - public LoopEnd loopEnd() { - for (Node usage : usages()) { - if (usage instanceof LoopEnd) { - LoopEnd end = (LoopEnd) usage; - if (end.loopBegin() == this) { - return end; - } - } - } - assert false : "Begin should always have a LoopEnd"; - return null; - } - - @Override - public void accept(ValueVisitor v) { - v.visitLoopBegin(this); - } - - @Override - public void print(LogStream out) { - out.print("loopBegin"); - } - - @Override - public String shortName() { - return "LoopBegin"; - } - - @Override - public Node copy(Graph into) { - LoopBegin x = new LoopBegin(into); - return x; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/LoopEnd.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/LoopEnd.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,81 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.ir; - -import com.oracle.graal.graph.*; -import com.sun.c1x.debug.*; - - -public class LoopEnd extends Merge { - - private static final int INPUT_COUNT = 1; - private static final int INPUT_LOOP_BEGIN = 0; - - private static final int SUCCESSOR_COUNT = 0; - - @Override - protected int inputCount() { - return super.inputCount() + INPUT_COUNT; - } - - @Override - protected int successorCount() { - return super.successorCount() + SUCCESSOR_COUNT; - } - - /** - * The instruction which produces the input value to this instruction. - */ - public LoopBegin loopBegin() { - return (LoopBegin) inputs().get(super.inputCount() + INPUT_LOOP_BEGIN); - } - - public LoopBegin setLoopBegin(LoopBegin n) { - return (LoopBegin) inputs().set(super.inputCount() + INPUT_LOOP_BEGIN, n); - } - - public LoopEnd(Graph graph) { - super(INPUT_COUNT, SUCCESSOR_COUNT, graph); - } - - @Override - public void accept(ValueVisitor v) { - v.visitLoopEnd(this); - } - - @Override - public void print(LogStream out) { - out.print("loopEnd ").print(loopBegin()); - } - - @Override - public String shortName() { - return "LoopEnd"; - } - - @Override - public Node copy(Graph into) { - LoopEnd x = new LoopEnd(into); - return x; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/Merge.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/Merge.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,282 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.ir; - -import com.oracle.graal.graph.*; -import com.sun.c1x.debug.*; -import com.sun.c1x.util.*; -import com.sun.c1x.value.*; -import com.sun.cri.ci.*; - -/** - * Denotes the beginning of a basic block, and holds information - * about the basic block, including the successor and - * predecessor blocks, exception handlers, liveness information, etc. - */ -public class Merge extends StateSplit { - - private static final int INPUT_COUNT = 0; - - private static final int SUCCESSOR_COUNT = 0; - - @Override - protected int inputCount() { - return super.inputCount() + INPUT_COUNT; - } - - @Override - protected int successorCount() { - return super.successorCount() + SUCCESSOR_COUNT; - } - - @Override - public boolean needsStateAfter() { - return false; - } - - /** - * Constructs a new Merge at the specified bytecode index. - * @param bci the bytecode index of the start - * @param blockID the ID of the block - * @param graph - */ - public Merge(Graph graph) { - super(CiKind.Illegal, INPUT_COUNT, SUCCESSOR_COUNT, graph); - } - - protected Merge(int inputCount, int successorCount, Graph graph) { - super(CiKind.Illegal, inputCount + INPUT_COUNT, successorCount + SUCCESSOR_COUNT, graph); - } - - @Override - public void accept(ValueVisitor v) { - v.visitMerge(this); - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("merge #"); - builder.append(id()); - builder.append(" ["); - - builder.append("]"); - - builder.append(" -> "); - boolean hasSucc = false; - for (Node s : this.successors()) { - if (hasSucc) { - builder.append(", "); - } - builder.append("#"); - if (s != null) { - builder.append(s.id()); - } else { - builder.append("null"); - } - hasSucc = true; - } - - return builder.toString(); - } - - public void printWithoutPhis(LogStream out) { - // print block id - out.print("B").print(id()).print(" "); - - // print flags - StringBuilder sb = new StringBuilder(8); - if (sb.length() != 0) { - out.print('(').print(sb.toString()).print(')'); - } - - // print block bci range - out.print('[').print(-1).print(", ").print(-1).print(']'); - - // print block successors - //if (end != null && end.blockSuccessors().size() > 0) { - out.print(" ."); - for (Node successor : this.successors()) { - if (successor instanceof Value) { - out.print((Value) successor); - } else { - out.print(successor.toString()); - } - } - //} - - // print predecessors -// if (!blockPredecessors().isEmpty()) { -// out.print(" pred:"); -// for (Instruction pred : blockPredecessors()) { -// out.print(pred.block()); -// } -// } - } - - @Override - public void print(LogStream out) { - - printWithoutPhis(out); - - // print phi functions - boolean hasPhisInLocals = false; - boolean hasPhisOnStack = false; - - //if (end() != null && end().stateAfter() != null) { - FrameState state = stateBefore(); - - int i = 0; - while (!hasPhisOnStack && i < state.stackSize()) { - Value value = state.stackAt(i); - hasPhisOnStack = isPhiAtBlock(value); - if (value != null && !(value instanceof Phi && ((Phi) value).isDead())) { - i += value.kind.sizeInSlots(); - } else { - i++; - } - } - - for (i = 0; !hasPhisInLocals && i < state.localsSize();) { - Value value = state.localAt(i); - hasPhisInLocals = isPhiAtBlock(value); - // also ignore illegal HiWords - if (value != null && !(value instanceof Phi && ((Phi) value).isDead())) { - i += value.kind.sizeInSlots(); - } else { - i++; - } - } - //} - - // print values in locals - if (hasPhisInLocals) { - out.println(); - out.println("Locals:"); - - int j = 0; - while (j < state.localsSize()) { - Value value = state.localAt(j); - if (value != null) { - out.println(stateString(j, value)); - // also ignore illegal HiWords - if (value instanceof Phi && ((Phi) value).isDead()) { - j += 1; - } else { - j += value.kind.sizeInSlots(); - } - } else { - j++; - } - } - out.println(); - } - - // print values on stack - if (hasPhisOnStack) { - out.println(); - out.println("Stack:"); - int j = 0; - while (j < stateBefore().stackSize()) { - Value value = stateBefore().stackAt(j); - if (value != null) { - out.println(stateString(j, value)); - j += value.kind.sizeInSlots(); - } else { - j++; - } - } - } - - } - - /** - * Determines if a given instruction is a phi whose {@linkplain Phi#block() join block} is a given block. - * - * @param value the instruction to test - * @param block the block that may be the join block of {@code value} if {@code value} is a phi - * @return {@code true} if {@code value} is a phi and its join block is {@code block} - */ - private boolean isPhiAtBlock(Value value) { - return value instanceof Phi && ((Phi) value).block() == this; - } - - - /** - * Formats a given instruction as a value in a {@linkplain FrameState frame state}. If the instruction is a phi defined at a given - * block, its {@linkplain Phi#valueCount() inputs} are appended to the returned string. - * - * @param index the index of the value in the frame state - * @param value the frame state value - * @param block if {@code value} is a phi, then its inputs are formatted if {@code block} is its - * {@linkplain Phi#block() join point} - * @return the instruction representation as a string - */ - public String stateString(int index, Value value) { - StringBuilder sb = new StringBuilder(30); - sb.append(String.format("%2d %s", index, Util.valueString(value))); - if (value instanceof Phi) { - Phi phi = (Phi) value; - // print phi operands - if (phi.block() == this) { - sb.append(" ["); - for (int j = 0; j < phi.valueCount(); j++) { - sb.append(' '); - Value operand = phi.valueAt(j); - if (operand != null) { - sb.append(Util.valueString(operand)); - } else { - sb.append("NULL"); - } - } - sb.append("] "); - } - } - return sb.toString(); - } - - @Override - public String shortName() { - return "Merge #" + id(); - } - - @Override - public Node copy(Graph into) { - assert getClass() == Merge.class : "copy of " + getClass(); - Merge x = new Merge(into); - return x; - } - - public void removePhiPredecessor(Node pred) { - int predIndex = predecessors().lastIndexOf(pred); - assert predIndex != -1; - - for (Node usage : usages()) { - if (usage instanceof Phi) { - Phi phi = (Phi) usage; -// assert phi.valueCount() == predecessors().size(); - phi.removeInput(predIndex); - } - } - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/MonitorAddress.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/MonitorAddress.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.ir; - -import com.oracle.graal.graph.*; -import com.sun.c1x.debug.*; -import com.sun.cri.ci.*; - -/** - * Instruction that is used to refer to the address of an on-stack monitor. - */ -public final class MonitorAddress extends Value { - - private static final int INPUT_COUNT = 0; - private static final int SUCCESSOR_COUNT = 0; - - private int monitor; - - public MonitorAddress(int monitor, Graph graph) { - super(CiKind.Word, INPUT_COUNT, SUCCESSOR_COUNT, graph); - this.monitor = monitor; - } - - @Override - public void accept(ValueVisitor v) { - v.visitMonitorAddress(this); - } - - public int monitor() { - return monitor; - } - - @Override - public void print(LogStream out) { - out.print("monitor_address (").print(monitor()).print(")"); - } - - @Override - public Node copy(Graph into) { - MonitorAddress x = new MonitorAddress(monitor, into); - return x; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/MonitorEnter.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/MonitorEnter.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.ir; - -import com.oracle.graal.graph.*; -import com.sun.c1x.debug.*; - -/** - * The {@code MonitorEnter} instruction represents the acquisition of a monitor. - */ -public final class MonitorEnter extends AccessMonitor { - - private static final int INPUT_COUNT = 0; - - private static final int SUCCESSOR_COUNT = 1; - - @Override - protected int successorCount() { - return super.successorCount() + SUCCESSOR_COUNT; - } - - /** - * Creates a new MonitorEnter instruction. - * - * @param object the instruction producing the object - * @param lockAddress the address of the on-stack lock object or {@code null} if the runtime does not place locks on the stack - * @param lockNumber the number of the lock - * @param graph - */ - public MonitorEnter(Value object, Value lockAddress, int lockNumber, Graph graph) { - super(object, lockAddress, lockNumber, INPUT_COUNT, SUCCESSOR_COUNT, graph); - } - - @Override - public void accept(ValueVisitor v) { - v.visitMonitorEnter(this); - } - - @Override - public void print(LogStream out) { - out.print("enter monitor[").print(lockNumber).print("](").print(object()).print(')'); - } - - @Override - public Node copy(Graph into) { - MonitorEnter x = new MonitorEnter(null, null, lockNumber, into); - return x; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/MonitorExit.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/MonitorExit.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.ir; - -import com.oracle.graal.graph.*; -import com.sun.c1x.debug.*; - -/** - * The {@code MonitorExit} instruction represents a monitor release. - */ -public final class MonitorExit extends AccessMonitor { - - private static final int INPUT_COUNT = 0; - private static final int SUCCESSOR_COUNT = 0; - - /** - * Creates a new MonitorExit instruction. - * - * @param object the instruction produces the object value - * @param lockAddress the address of the on-stack lock object or {@code null} if the runtime does not place locks on the stack - * @param lockNumber the number of the lock - * @param graph - */ - public MonitorExit(Value object, Value lockAddress, int lockNumber, Graph graph) { - super(object, lockAddress, lockNumber, INPUT_COUNT, SUCCESSOR_COUNT, graph); - } - - @Override - public void accept(ValueVisitor v) { - v.visitMonitorExit(this); - } - - @Override - public void print(LogStream out) { - out.print("exit monitor[").print(lockNumber).print("](").print(object()).print(')'); - } - - @Override - public Node copy(Graph into) { - MonitorExit x = new MonitorExit(null, null, lockNumber, into); - return x; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/Negate.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/Negate.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,106 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.ir; - -import com.oracle.graal.graph.*; -import com.sun.c1x.debug.*; -import com.sun.c1x.util.*; -import com.sun.cri.bytecode.*; -import com.sun.cri.ci.*; - -/** - * The {@code NegateOp} instruction negates its operand. - */ -public final class Negate extends FloatingNode { - - private static final int INPUT_COUNT = 2; - private static final int INPUT_X = 0; - private static final int INPUT_Y = 1; - - private static final int SUCCESSOR_COUNT = 0; - - @Override - protected int inputCount() { - return super.inputCount() + INPUT_COUNT; - } - - @Override - protected int successorCount() { - return super.successorCount() + SUCCESSOR_COUNT; - } - - /** - * The instruction producing input to this instruction. - */ - public Value x() { - return (Value) inputs().get(super.inputCount() + INPUT_X); - } - - public Value setX(Value n) { - return (Value) inputs().set(super.inputCount() + INPUT_X, n); - } - - /** - * Creates new NegateOp instance. - * @param x the instruction producing the value that is input to this instruction - */ - public Negate(Value x, Graph graph) { - super(x.kind, INPUT_COUNT, SUCCESSOR_COUNT, graph); - setX(x); - } - - // for copying - private Negate(CiKind kind, Graph graph) { - super(kind, INPUT_COUNT, SUCCESSOR_COUNT, graph); - } - - @Override - public void accept(ValueVisitor v) { - v.visitNegate(this); - } - - @Override - public int valueNumber() { - return Util.hash1(Bytecodes.INEG, x()); - } - - @Override - public boolean valueEqual(Node i) { - if (i instanceof Negate) { - Negate o = (Negate) i; - return x() == o.x(); - } - return false; - } - - @Override - public void print(LogStream out) { - out.print("- ").print(x()); - } - - @Override - public Node copy(Graph into) { - Negate x = new Negate(kind, into); - return x; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/NewArray.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/NewArray.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.ir; - -import com.oracle.graal.graph.*; -import com.sun.cri.ci.*; - -/** - * The {@code NewArray} class is the base of all instructions that allocate arrays. - */ -public abstract class NewArray extends Instruction { - - private static final int INPUT_COUNT = 1; - private static final int INPUT_LENGTH = 0; - - private static final int SUCCESSOR_COUNT = 0; - - @Override - protected int inputCount() { - return super.inputCount() + INPUT_COUNT; - } - - @Override - protected int successorCount() { - return super.successorCount() + SUCCESSOR_COUNT; - } - - /** - * The instruction that produces the length of this array. - */ - public Value length() { - return (Value) inputs().get(super.inputCount() + INPUT_LENGTH); - } - - public Value setLength(Value n) { - return (Value) inputs().set(super.inputCount() + INPUT_LENGTH, n); - } - - /** - * Constructs a new NewArray instruction. - * @param length the instruction that produces the length for this allocation - * @param stateBefore the state before the allocation - * @param inputCount - * @param successorCount - * @param graph - */ - NewArray(Value length, int inputCount, int successorCount, Graph graph) { - super(CiKind.Object, inputCount + INPUT_COUNT, successorCount + SUCCESSOR_COUNT, graph); - setLength(length); - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/NewInstance.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/NewInstance.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,89 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.ir; - -import com.oracle.graal.graph.*; -import com.sun.c1x.debug.*; -import com.sun.cri.ci.*; -import com.sun.cri.ri.*; - -/** - * The {@code NewInstance} instruction represents the allocation of an instance class object. - */ -public final class NewInstance extends FloatingNode { - - private static final int INPUT_COUNT = 0; - private static final int SUCCESSOR_COUNT = 0; - - final RiType instanceClass; - public final int cpi; - public final RiConstantPool constantPool; - - /** - * Constructs a NewInstance instruction. - * @param type the class being allocated - * @param cpi the constant pool index - * @param stateBefore the state before executing this instruction - * @param graph - */ - public NewInstance(RiType type, int cpi, RiConstantPool constantPool, Graph graph) { - super(CiKind.Object, INPUT_COUNT, SUCCESSOR_COUNT, graph); - this.instanceClass = type; - this.cpi = cpi; - this.constantPool = constantPool; - } - - /** - * Gets the instance class being allocated by this instruction. - * @return the instance class allocated - */ - public RiType instanceClass() { - return instanceClass; - } - - /** - * Gets the exact type produced by this instruction. For allocations of instance classes, this is - * always the class allocated. - * @return the exact type produced by this instruction - */ - @Override - public RiType exactType() { - return instanceClass; - } - - @Override - public void accept(ValueVisitor v) { - v.visitNewInstance(this); - } - - @Override - public void print(LogStream out) { - out.print("new instance ").print(CiUtil.toJavaName(instanceClass())); - } - - @Override - public Node copy(Graph into) { - NewInstance x = new NewInstance(instanceClass, cpi, constantPool, into); - return x; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/NewMultiArray.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/NewMultiArray.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,125 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.ir; - -import com.oracle.graal.graph.*; -import com.sun.c1x.debug.*; -import com.sun.cri.ci.*; -import com.sun.cri.ri.*; - -/** - * The {@code NewMultiArray} instruction represents an allocation of a multi-dimensional object - * array. - */ -public final class NewMultiArray extends NewArray { - - private final int dimensionCount; - - private static final int SUCCESSOR_COUNT = 0; - - @Override - protected int inputCount() { - return super.inputCount() + dimensionCount; - } - - @Override - protected int successorCount() { - return super.successorCount() + SUCCESSOR_COUNT; - } - - /** - * The list of instructions which produce input for this instruction. - */ - public Value dimension(int index) { - assert index >= 0 && index < dimensionCount; - return (Value) inputs().get(super.inputCount() + index); - } - - public Value setDimension(int index, Value n) { - assert index >= 0 && index < dimensionCount; - return (Value) inputs().set(super.inputCount() + index, n); - } - - /** - * The rank of the array allocated by this instruction, i.e. how many array dimensions. - */ - public int dimensionCount() { - return dimensionCount; - } - - public final RiType elementType; - public final int cpi; - public final RiConstantPool constantPool; - - /** - * Constructs a new NewMultiArray instruction. - * @param elementType the element type of the array - * @param dimensions the instructions which produce the dimensions for this array - * @param stateBefore the state before this instruction - * @param cpi the constant pool index for resolution - * @param riConstantPool the constant pool for resolution - * @param graph - */ - public NewMultiArray(RiType elementType, Value[] dimensions, int cpi, RiConstantPool riConstantPool, Graph graph) { - super(null, dimensions.length, SUCCESSOR_COUNT, graph); - this.constantPool = riConstantPool; - this.elementType = elementType; - this.cpi = cpi; - - this.dimensionCount = dimensions.length; - for (int i = 0; i < dimensions.length; i++) { - setDimension(i, dimensions[i]); - } - } - - @Override - public void accept(ValueVisitor v) { - v.visitNewMultiArray(this); - } - - /** - * Gets the element type of the array. - * @return the element type of the array - */ - public RiType elementType() { - return elementType; - } - - @Override - public void print(LogStream out) { - out.print("new multi array ["); - for (int i = 0; i < dimensionCount; i++) { - if (i > 0) { - out.print(", "); - } - out.print(dimension(i)); - } - out.print("] ").print(CiUtil.toJavaName(elementType)); - } - - @Override - public Node copy(Graph into) { - NewMultiArray x = new NewMultiArray(elementType, new Value[dimensionCount], cpi, constantPool, into); - return x; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/NewObjectArray.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/NewObjectArray.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,84 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.ir; - -import com.oracle.graal.graph.*; -import com.sun.c1x.debug.*; -import com.sun.cri.ci.*; -import com.sun.cri.ri.*; - -/** - * The {@code NewObjectArray} instruction represents an allocation of an object array. - */ -public final class NewObjectArray extends NewArray { - - private static final int INPUT_COUNT = 0; - private static final int SUCCESSOR_COUNT = 0; - - final RiType elementClass; - - /** - * Constructs a new NewObjectArray instruction. - * @param elementClass the class of elements in this array - * @param length the instruction producing the length of the array - * @param graph - */ - public NewObjectArray(RiType elementClass, Value length, Graph graph) { - super(length, INPUT_COUNT, SUCCESSOR_COUNT, graph); - this.elementClass = elementClass; - } - - /** - * Gets the type of the elements of the array. - * @return the element type of the array - */ - public RiType elementClass() { - return elementClass; - } - - @Override - public RiType exactType() { - return elementClass.arrayOf(); - } - - @Override - public RiType declaredType() { - return exactType(); - } - - @Override - public void accept(ValueVisitor v) { - v.visitNewObjectArray(this); - } - - @Override - public void print(LogStream out) { - out.print("new object array [").print(length()).print("] ").print(CiUtil.toJavaName(elementClass())); - } - - @Override - public Node copy(Graph into) { - NewObjectArray x = new NewObjectArray(elementClass, null, into); - return x; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/NewTypeArray.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/NewTypeArray.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,74 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.ir; - -import com.oracle.graal.graph.*; -import com.sun.c1x.debug.*; -import com.sun.cri.ci.*; -import com.sun.cri.ri.*; - -/** - * The {@code NewTypeArray} class definition. - */ -public final class NewTypeArray extends NewArray { - - private static final int INPUT_COUNT = 0; - private static final int SUCCESSOR_COUNT = 0; - - final RiType elementType; - - public NewTypeArray(Value length, RiType elementType, Graph graph) { - super(length, INPUT_COUNT, SUCCESSOR_COUNT, graph); - this.elementType = elementType; - } - - public CiKind elementKind() { - return elementType.kind(); - } - - @Override - public RiType declaredType() { - return elementType.arrayOf(); - } - - @Override - public RiType exactType() { - return elementType.arrayOf(); - } - - @Override - public void accept(ValueVisitor v) { - v.visitNewTypeArray(this); - } - - @Override - public void print(LogStream out) { - out.print("new ").print(elementKind().name()).print(" array [").print(length()).print(']'); - } - - @Override - public Node copy(Graph into) { - NewTypeArray x = new NewTypeArray(null, elementType, into); - return x; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/NormalizeCompare.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/NormalizeCompare.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.ir; - -import com.oracle.graal.graph.*; -import com.sun.c1x.debug.*; -import com.sun.cri.bytecode.*; -import com.sun.cri.ci.*; - -/** - * Returns -1, 0, or 1 if either x > y, x == y, or x < y. - */ -public final class NormalizeCompare extends Binary { - - private static final int INPUT_COUNT = 0; - private static final int SUCCESSOR_COUNT = 0; - - /** - * Creates a new compare operation. - * @param opcode the bytecode opcode - * @param kind the result kind - * @param x the first input - * @param y the second input - */ - public NormalizeCompare(int opcode, CiKind kind, Value x, Value y, Graph graph) { - super(kind, opcode, x, y, INPUT_COUNT, SUCCESSOR_COUNT, graph); - } - - @Override - public void accept(ValueVisitor v) { - v.visitMaterialize(this); - } - - @Override - public void print(LogStream out) { - out.print(x()). - print(' '). - print(Bytecodes.operator(opcode)). - print(' '). - print(y()); - } - - @Override - public Node copy(Graph into) { - return new NormalizeCompare(opcode, kind, null, null, into); - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/NullCheck.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/NullCheck.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,120 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.ir; - -import com.oracle.graal.graph.*; -import com.sun.c1x.debug.*; -import com.sun.c1x.util.*; -import com.sun.cri.bytecode.*; -import com.sun.cri.ci.*; -import com.sun.cri.ri.*; - -/** - * The {@code NullCheck} class represents an explicit null check instruction. - */ -public final class NullCheck extends Instruction { - - private static final int INPUT_COUNT = 1; - private static final int INPUT_OBJECT = 0; - - private static final int SUCCESSOR_COUNT = 0; - - @Override - protected int inputCount() { - return super.inputCount() + INPUT_COUNT; - } - - @Override - protected int successorCount() { - return super.successorCount() + SUCCESSOR_COUNT; - } - - /** - * The instruction that produces the object tested against null. - */ - public Value object() { - return (Value) inputs().get(super.inputCount() + INPUT_OBJECT); - } - - public Value setObject(Value n) { - return (Value) inputs().set(super.inputCount() + INPUT_OBJECT, n); - } - - /** - * Constructs a new NullCheck instruction. - * @param object the instruction producing the object to check against null - * @param stateBefore the state before executing the null check - * @param graph - */ - public NullCheck(Value object, Graph graph) { - super(object.kind, INPUT_COUNT, SUCCESSOR_COUNT, graph); - setObject(object); - } - - // for copying - private NullCheck(CiKind kind, Graph graph) { - super(kind, INPUT_COUNT, SUCCESSOR_COUNT, graph); - } - - @Override - public void accept(ValueVisitor v) { - v.visitNullCheck(this); - } - - @Override - public int valueNumber() { - return Util.hash1(Bytecodes.IFNONNULL, object()); - } - - @Override - public boolean valueEqual(Node i) { - if (i instanceof NullCheck) { - NullCheck o = (NullCheck) i; - return object() == o.object(); - } - return false; - } - - @Override - public RiType declaredType() { - // null check does not alter the type of the object - return object().declaredType(); - } - - @Override - public RiType exactType() { - // null check does not alter the type of the object - return object().exactType(); - } - - @Override - public void print(LogStream out) { - out.print("null_check(").print(object()).print(')'); - } - - @Override - public Node copy(Graph into) { - NullCheck x = new NullCheck(kind, into); - return x; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/Or.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/Or.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,116 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.ir; - -import com.oracle.graal.graph.*; -import com.oracle.max.graal.opt.CanonicalizerPhase.*; -import com.sun.cri.bytecode.*; -import com.sun.cri.ci.*; - - -/** - * - */ -public final class Or extends Logic { - private static final OrCanonicalizerOp CANONICALIZER = new OrCanonicalizerOp(); - - /** - * @param opcode - * @param kind - * @param x - * @param y - * @param graph - */ - public Or(CiKind kind, Value x, Value y, Graph graph) { - super(kind, kind == CiKind.Int ? Bytecodes.IOR : Bytecodes.LOR, x, y, graph); - } - - @Override - public String shortName() { - return "|"; - } - - @Override - public Node copy(Graph into) { - Or x = new Or(kind, null, null, into); - return x; - } - - @SuppressWarnings("unchecked") - @Override - public T lookup(Class clazz) { - if (clazz == CanonicalizerOp.class) { - return (T) CANONICALIZER; - } - return super.lookup(clazz); - } - - private static class OrCanonicalizerOp implements CanonicalizerOp { - @Override - public Node canonical(Node node) { - assert node instanceof Or; - Or or = (Or) node; - CiKind kind = or.kind; - Graph graph = or.graph(); - Value x = or.x(); - Value y = or.y(); - if (x == y) { - return x; - } - if (x.isConstant() && !y.isConstant()) { - or.swapOperands(); - Value t = y; - y = x; - x = t; - } - if (x.isConstant()) { - if (kind == CiKind.Int) { - return Constant.forInt(x.asConstant().asInt() | y.asConstant().asInt(), graph); - } else { - assert kind == CiKind.Long; - return Constant.forLong(x.asConstant().asLong() | y.asConstant().asLong(), graph); - } - } else if (y.isConstant()) { - if (kind == CiKind.Int) { - int c = y.asConstant().asInt(); - if (c == -1) { - return Constant.forInt(-1, graph); - } - if (c == 0) { - return x; - } - } else { - assert kind == CiKind.Long; - long c = y.asConstant().asLong(); - if (c == -1) { - return Constant.forLong(-1, graph); - } - if (c == 0) { - return x; - } - } - } - return or; - } - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/Phi.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/Phi.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,179 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.ir; - -import com.oracle.graal.graph.*; -import com.sun.c1x.debug.*; -import com.sun.cri.ci.*; - -/** - * The {@code Phi} instruction represents the merging of dataflow - * in the instruction graph. It refers to a join block and a variable. - */ -public final class Phi extends FixedNode { - - private static final int DEFAULT_MAX_VALUES = 2; - - private static final int INPUT_COUNT = 1; - private static final int INPUT_BLOCK = 0; - - private final int maxValues; - - private static final int SUCCESSOR_COUNT = 0; - - private int usedInputCount; - private boolean isDead; - - @Override - protected int inputCount() { - return super.inputCount() + INPUT_COUNT + maxValues; - } - - @Override - protected int successorCount() { - return super.successorCount() + SUCCESSOR_COUNT; - } - - /** - * The join block for this phi. - */ - public Merge block() { - return (Merge) inputs().get(super.inputCount() + INPUT_BLOCK); - } - - public Value setBlock(Value n) { - return (Merge) inputs().set(super.inputCount() + INPUT_BLOCK, n); - } - - /** - * Create a new Phi for the specified join block and local variable (or operand stack) slot. - * @param kind the type of the variable - * @param block the join point - * @param graph - */ - public Phi(CiKind kind, Merge block, Graph graph) { - this(kind, block, DEFAULT_MAX_VALUES, graph); - } - - public Phi(CiKind kind, Merge block, int maxValues, Graph graph) { - super(kind, INPUT_COUNT + maxValues, SUCCESSOR_COUNT, graph); - this.maxValues = maxValues; - usedInputCount = 0; - setBlock(block); - } - - /** - * Get the instruction that produces the value associated with the i'th predecessor - * of the join block. - * @param i the index of the predecessor - * @return the instruction that produced the value in the i'th predecessor - */ - public Value valueAt(int i) { - return (Value) inputs().get(INPUT_COUNT + i); - } - - public Node setValueAt(int i, Node x) { - return inputs().set(INPUT_COUNT + i, x); - } - - /** - * Get the number of inputs to this phi (i.e. the number of predecessors to the join block). - * @return the number of inputs in this phi - */ - public int valueCount() { - return usedInputCount; - } - - @Override - public void accept(ValueVisitor v) { - v.visitPhi(this); - } - - /** - * Make this phi illegal if types were not merged correctly. - */ - public void makeDead() { - isDead = true; - } - - public boolean isDead() { - return isDead; - } - - @Override - public void print(LogStream out) { - out.print("phi function ("); - for (int i = 0; i < valueCount(); ++i) { - if (i != 0) { - out.print(' '); - } - out.print(valueAt(i)); - } - out.print(')'); - } - - @Override - public String shortName() { - StringBuilder str = new StringBuilder(); - for (int i = 0; i < valueCount(); ++i) { - if (i != 0) { - str.append(' '); - } - str.append(valueAt(i) == null ? "-" : valueAt(i).id()); - } - return "Phi: (" + str + ")"; - } - - public Phi addInput(Node y) { - assert !this.isDeleted() && !y.isDeleted(); - Phi phi = this; - if (usedInputCount == maxValues) { - phi = new Phi(kind, block(), maxValues * 2, graph()); - for (int i = 0; i < valueCount(); ++i) { - phi.addInput(valueAt(i)); - } - phi.addInput(y); - this.replace(phi); - } else { - setValueAt(usedInputCount++, y); - } - return phi; - } - - public void removeInput(int index) { - assert index < valueCount() : "index: " + index + ", valueCount: " + valueCount() + "@phi " + id(); - setValueAt(index, Node.Null); - for (int i = index + 1; i < valueCount(); ++i) { - setValueAt(i - 1, valueAt(i)); - } - usedInputCount--; - } - - @Override - public Node copy(Graph into) { - Phi x = new Phi(kind, null, maxValues, into); - x.usedInputCount = usedInputCount; - x.isDead = isDead; - return x; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/Placeholder.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/Placeholder.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.ir; - -import com.oracle.graal.graph.*; -import com.sun.c1x.debug.*; -import com.sun.cri.ci.*; - - -public class Placeholder extends StateSplit { - - private static final int INPUT_COUNT = 0; - - private static final int SUCCESSOR_COUNT = 0; - - @Override - protected int inputCount() { - return super.inputCount() + INPUT_COUNT; - } - - @Override - protected int successorCount() { - return super.successorCount() + SUCCESSOR_COUNT; - } - - public Placeholder(Graph graph) { - super(CiKind.Void, INPUT_COUNT, SUCCESSOR_COUNT, graph); - } - - @Override - public void accept(ValueVisitor v) { - assert false; - } - - @Override - public void print(LogStream out) { - assert false; - } - - @Override - public String shortName() { - return "Placeholder" + id(); - } - - @Override - public Node copy(Graph into) { - Placeholder x = new Placeholder(into); - return x; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/RegisterFinalizer.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/RegisterFinalizer.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,82 +0,0 @@ -/* - * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.ir; - -import com.oracle.graal.graph.*; -import com.sun.c1x.debug.*; -import com.sun.c1x.value.*; -import com.sun.cri.ci.*; - -/** - * This instruction is used to perform the finalizer registration at the end of the java.lang.Object constructor. - */ -public class RegisterFinalizer extends StateSplit { - - private static final int INPUT_COUNT = 1; - private static final int INPUT_OBJECT = 0; - - private static final int SUCCESSOR_COUNT = 0; - - @Override - protected int inputCount() { - return super.inputCount() + INPUT_COUNT; - } - - @Override - protected int successorCount() { - return super.successorCount() + SUCCESSOR_COUNT; - } - - /** - * The instruction that produces the object whose finalizer should be registered. - */ - public Value object() { - return (Value) inputs().get(super.inputCount() + INPUT_OBJECT); - } - - public Value setObject(Value n) { - return (Value) inputs().set(super.inputCount() + INPUT_OBJECT, n); - } - - public RegisterFinalizer(Value object, FrameState stateBefore, Graph graph) { - super(CiKind.Void, INPUT_COUNT, SUCCESSOR_COUNT, graph); - setObject(object); - setStateBefore(stateBefore); - } - - @Override - public void accept(ValueVisitor v) { - v.visitRegisterFinalizer(this); - } - - @Override - public void print(LogStream out) { - out.print("register finalizer ").print(object()); - } - - @Override - public Node copy(Graph into) { - RegisterFinalizer x = new RegisterFinalizer(null, null, into); - return x; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/Return.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/Return.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,101 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.ir; - -import com.oracle.graal.graph.*; -import com.sun.c1x.debug.*; -import com.sun.cri.ci.*; - -/** - * The {@code Return} class definition. - */ -public final class Return extends BlockEnd { - - private static final int INPUT_COUNT = 1; - private static final int INPUT_RESULT = 0; - - private static final int SUCCESSOR_COUNT = 1; - private static final int SUCCESSOR_END = 0; - - @Override - protected int inputCount() { - return super.inputCount() + INPUT_COUNT; - } - - @Override - protected int successorCount() { - return super.successorCount() + SUCCESSOR_COUNT; - } - - /** - * The instruction that produces the result for the return. - */ - public Value result() { - return (Value) inputs().get(super.inputCount() + INPUT_RESULT); - } - - public Value setResult(Value n) { - return (Value) inputs().set(super.inputCount() + INPUT_RESULT, n); - } - - @Override - public Instruction next() { - return null; - } - - /** - * Constructs a new Return instruction. - * @param result the instruction producing the result for this return; {@code null} if this - * is a void return - * @param graph - */ - public Return(Value result, Graph graph) { - super(result == null ? CiKind.Void : result.kind, 0, INPUT_COUNT, SUCCESSOR_COUNT, graph); - setResult(result); - } - - // for copying - private Return(CiKind kind, Graph graph) { - super(kind, 0, INPUT_COUNT, SUCCESSOR_COUNT, graph); - } - - @Override - public void accept(ValueVisitor v) { - v.visitReturn(this); - } - - @Override - public void print(LogStream out) { - if (result() == null) { - out.print("return"); - } else { - out.print(kind.typeChar).print("return ").print(result()); - } - } - - @Override - public Node copy(Graph into) { - Return x = new Return(kind, into); - return x; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/RightShift.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/RightShift.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.ir; - -import com.oracle.graal.graph.*; -import com.sun.cri.bytecode.*; -import com.sun.cri.ci.*; - - -public final class RightShift extends Shift { - - /** - * @param opcode - * @param kind - * @param x - * @param y - * @param graph - */ - public RightShift(CiKind kind, Value x, Value y, Graph graph) { - super(kind, kind == CiKind.Int ? Bytecodes.ISHR : Bytecodes.LSHR, x, y, graph); - } - - @Override - public String shortName() { - return ">>"; - } - - @Override - public Node copy(Graph into) { - RightShift rs = new RightShift(kind, null, null, graph()); - return rs; - } - -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/Shift.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/Shift.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.ir; - -import com.oracle.graal.graph.*; -import com.sun.c1x.debug.*; -import com.sun.cri.ci.*; - -/** - * The {@code ShiftOp} class represents shift operations. - */ -public abstract class Shift extends Binary { - - private static final int INPUT_COUNT = 0; - private static final int SUCCESSOR_COUNT = 0; - - /** - * Creates a new shift operation. - * @param opcode the opcode of the shift - * @param x the first input value - * @param y the second input value - */ - public Shift(CiKind kind, int opcode, Value x, Value y, Graph graph) { - super(kind, opcode, x, y, INPUT_COUNT, SUCCESSOR_COUNT, graph); - } - - @Override - public void accept(ValueVisitor v) { - v.visitShift(this); - } - - @Override - public void print(LogStream out) { - out.print(x()).print(' ').print(this.shortName()).print(' ').print(y()); - } - - @Override - public abstract String shortName(); -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/StateSplit.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/StateSplit.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,95 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.ir; - -import com.oracle.graal.graph.*; -import com.sun.c1x.value.*; -import com.sun.cri.ci.*; - -/** - * The {@code StateSplit} class is the abstract base class of all instructions - * that store an immutable copy of the frame state. - */ -public abstract class StateSplit extends Instruction { - - private static final int INPUT_COUNT = 1; - private static final int INPUT_STATE_BEFORE = 0; - - private static final int SUCCESSOR_COUNT = 1; - private static final int SUCCESSOR_STATE_AFTER = 0; - - @Override - protected int inputCount() { - return super.inputCount() + INPUT_COUNT; - } - - @Override - protected int successorCount() { - return super.successorCount() + SUCCESSOR_COUNT; - } - - /** - * The state for this instruction. - */ - public FrameState stateBefore() { - return (FrameState) inputs().get(super.inputCount() + INPUT_STATE_BEFORE); - } - - public FrameState setStateBefore(FrameState n) { - FrameState oldState = stateBefore(); - try { - return (FrameState) inputs().set(super.inputCount() + INPUT_STATE_BEFORE, n); - } finally { - if (oldState != n && oldState != null) { - oldState.delete(); - } - } - } - - /** - * The state for this instruction. - */ - @Override - public FrameState stateAfter() { - return (FrameState) successors().get(super.successorCount() + SUCCESSOR_STATE_AFTER); - } - - public FrameState setStateAfter(FrameState n) { - return (FrameState) successors().set(super.successorCount() + SUCCESSOR_STATE_AFTER, n); - } - - /** - * Creates a new state split with the specified value type. - * @param kind the type of the value that this instruction produces - * @param inputCount - * @param successorCount - * @param graph - */ - public StateSplit(CiKind kind, int inputCount, int successorCount, Graph graph) { - super(kind, inputCount + INPUT_COUNT, successorCount + SUCCESSOR_COUNT, graph); - } - - public boolean needsStateAfter() { - return true; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/StoreField.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/StoreField.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,95 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.ir; - -import com.oracle.graal.graph.*; -import com.sun.c1x.debug.*; -import com.sun.cri.ci.*; -import com.sun.cri.ri.*; - -/** - * The {@code StoreField} instruction represents a write to a static or instance field. - */ -public final class StoreField extends AccessField { - - private static final int INPUT_COUNT = 1; - private static final int INPUT_VALUE = 0; - - private static final int SUCCESSOR_COUNT = 0; - - @Override - protected int inputCount() { - return super.inputCount() + INPUT_COUNT; - } - - @Override - protected int successorCount() { - return super.successorCount() + SUCCESSOR_COUNT; - } - - /** - * The value that is written to the field. - */ - public Value value() { - return (Value) inputs().get(super.inputCount() + INPUT_VALUE); - } - - public Value setValue(Value n) { - return (Value) inputs().set(super.inputCount() + INPUT_VALUE, n); - } - - /** - * Creates a new LoadField instance. - * @param object the receiver object - * @param field the compiler interface field - * @param value the instruction representing the value to store to the field - * @param stateAfter the state after the field access - * @param graph - */ - public StoreField(Value object, RiField field, Value value, Graph graph) { - super(CiKind.Void, object, field, INPUT_COUNT, SUCCESSOR_COUNT, graph); - setValue(value); - } - - @Override - public void accept(ValueVisitor v) { - v.visitStoreField(this); - } - - @Override - public void print(LogStream out) { - out.print(object()). - print("."). - print(field().name()). - print(" := "). - print(value()). - print(" [type: ").print(CiUtil.format("%h.%n:%t", field(), false)). - print(']'); - } - - @Override - public Node copy(Graph into) { - StoreField x = new StoreField(null, field, null, into); - return x; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/StoreIndexed.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/StoreIndexed.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,90 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.ir; - -import com.oracle.graal.graph.*; -import com.sun.c1x.debug.*; -import com.sun.cri.ci.*; - -/** - * The {@code StoreIndexed} instruction represents a write to an array element. - */ -public final class StoreIndexed extends AccessIndexed { - - private static final int INPUT_COUNT = 1; - private static final int INPUT_VALUE = 0; - - private static final int SUCCESSOR_COUNT = 0; - - @Override - protected int inputCount() { - return super.inputCount() + INPUT_COUNT; - } - - @Override - protected int successorCount() { - return super.successorCount() + SUCCESSOR_COUNT; - } - - /** - * The instruction that produces the value that is to be stored into the array. - */ - public Value value() { - return (Value) inputs().get(super.inputCount() + INPUT_VALUE); - } - - public Value setValue(Value n) { - return (Value) inputs().set(super.inputCount() + INPUT_VALUE, n); - } - - /** - * Creates a new StoreIndexed instruction. - * @param array the instruction producing the array - * @param index the instruction producing the index - * @param length the instruction producing the length - * @param elementKind the element type - * @param value the value to store into the array - * @param stateAfter the state after executing this instruction - * @param graph - */ - public StoreIndexed(Value array, Value index, Value length, CiKind elementKind, Value value, Graph graph) { - super(CiKind.Void, array, index, length, elementKind, INPUT_COUNT, SUCCESSOR_COUNT, graph); - setValue(value); - } - - @Override - public void accept(ValueVisitor v) { - v.visitStoreIndexed(this); - } - - @Override - public void print(LogStream out) { - out.print(array()).print('[').print(index()).print("] := ").print(value()).print(" (").print(kind.typeChar).print(')'); - } - - @Override - public Node copy(Graph into) { - StoreIndexed x = new StoreIndexed(null, null, null, elementKind(), null, into); - return x; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/Switch.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/Switch.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,81 +0,0 @@ -/* - * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.ir; - -import java.util.*; - -import com.oracle.graal.graph.*; -import com.sun.cri.ci.*; - -/** - * The {@code Switch} class is the base of both lookup and table switches. - */ -public abstract class Switch extends BlockEnd { - - private static final int INPUT_COUNT = 1; - private static final int INPUT_VALUE = 0; - - private static final int SUCCESSOR_COUNT = 0; - - @Override - protected int inputCount() { - return super.inputCount() + INPUT_COUNT; - } - - @Override - protected int successorCount() { - return super.successorCount() + SUCCESSOR_COUNT; - } - - /** - * The instruction that provides the input value to this switch. - */ - public Value value() { - return (Value) inputs().get(super.inputCount() + INPUT_VALUE); - } - - public Value setValue(Value n) { - return (Value) inputs().set(super.inputCount() + INPUT_VALUE, n); - } - - /** - * Constructs a new Switch. - * @param value the instruction that provides the value to be switched over - * @param successors the list of successors of this switch - * @param stateAfter the state after the switch - * @param graph - */ - public Switch(Value value, List successors, int inputCount, int successorCount, Graph graph) { - super(CiKind.Illegal, successors, inputCount + INPUT_COUNT, successorCount + SUCCESSOR_COUNT, graph); - setValue(value); - } - - /** - * Gets the number of cases that this switch covers (excluding the default case). - * @return the number of cases - */ - public int numberOfCases() { - return blockSuccessorCount() - 1; - } - -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/TableSwitch.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/TableSwitch.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,94 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.ir; - -import static com.sun.c1x.debug.InstructionPrinter.InstructionLineColumn.*; - -import java.util.*; - -import com.oracle.graal.graph.*; -import com.sun.c1x.debug.*; - -/** - * The {@code TableSwitch} instruction represents a table switch. - */ -public final class TableSwitch extends Switch { - - private static final int INPUT_COUNT = 0; - private static final int SUCCESSOR_COUNT = 0; - - final int lowKey; - - /** - * Constructs a new TableSwitch instruction. - * @param value the instruction producing the value being switched on - * @param successors the list of successors - * @param lowKey the lowest integer key in the table - * @param stateAfter the state after the switch - * @param graph - */ - public TableSwitch(Value value, List successors, int lowKey, Graph graph) { - super(value, successors, INPUT_COUNT, SUCCESSOR_COUNT, graph); - this.lowKey = lowKey; - } - - /** - * Gets the lowest key in the table switch (inclusive). - * @return the low key - */ - public int lowKey() { - return lowKey; - } - - /** - * Gets the highest key in the table switch (exclusive). - * @return the high key - */ - public int highKey() { - return lowKey + numberOfCases(); - } - - @Override - public void accept(ValueVisitor v) { - v.visitTableSwitch(this); - } - - @Override - public void print(LogStream out) { - out.print("tableswitch "); - out.println(value()); - int l = numberOfCases(); - for (int i = 0; i < l; i++) { - INSTRUCTION.advance(out); - out.printf("case %5d: B%d%n", lowKey() + i, blockSuccessors().get(i)); - } - INSTRUCTION.advance(out); - out.print("default : ").print(defaultSuccessor()); - } - - @Override - public Node copy(Graph into) { - TableSwitch x = new TableSwitch(null, Arrays.asList(new Instruction[numberOfCases() + 1]), lowKey, into); - return x; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/TypeCheck.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/TypeCheck.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,107 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.ir; - -import com.oracle.graal.graph.*; -import com.sun.cri.ci.*; -import com.sun.cri.ri.*; - -/** - * The {@code TypeCheck} instruction is the base class of casts and instanceof tests. - */ -public abstract class TypeCheck extends FloatingNode { - - private static final int INPUT_COUNT = 2; - private static final int INPUT_OBJECT = 0; - private static final int INPUT_TARGET_CLASS_INSTRUCTION = 1; - - private static final int SUCCESSOR_COUNT = 0; - - @Override - protected int inputCount() { - return super.inputCount() + INPUT_COUNT; - } - - @Override - protected int successorCount() { - return super.successorCount() + SUCCESSOR_COUNT; - } - - /** - * The instruction which produces the object input. - */ - public Value object() { - return (Value) inputs().get(super.inputCount() + INPUT_OBJECT); - } - - public Value setObject(Value n) { - return (Value) inputs().set(super.inputCount() + INPUT_OBJECT, n); - } - - /** - * The instruction that loads the target class object that is used by this checkcast. - */ - public Value targetClassInstruction() { - return (Value) inputs().get(super.inputCount() + INPUT_TARGET_CLASS_INSTRUCTION); - } - - public Value setTargetClassInstruction(Value n) { - return (Value) inputs().set(super.inputCount() + INPUT_TARGET_CLASS_INSTRUCTION, n); - } - - final RiType targetClass; - - /** - * Creates a new TypeCheck instruction. - * @param targetClass the class which is being casted to or checked against - * @param object the instruction which produces the object - * @param kind the result type of this instruction - * @param stateBefore the state before this instruction is executed - * @param inputCount - * @param successorCount - * @param graph - */ - public TypeCheck(RiType targetClass, Value targetClassInstruction, Value object, CiKind kind, int inputCount, int successorCount, Graph graph) { - super(kind, inputCount + INPUT_COUNT, successorCount + SUCCESSOR_COUNT, graph); - this.targetClass = targetClass; - setObject(object); - setTargetClassInstruction(targetClassInstruction); - } - - /** - * Gets the target class, i.e. the class being cast to, or the class being tested against. - * @return the target class - */ - public RiType targetClass() { - return targetClass; - } - - /** - * Checks whether the target class of this instruction is loaded. - * @return {@code true} if the target class is loaded - */ - public boolean isLoaded() { - return targetClass != null; - } - -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/UnsignedRightShift.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/UnsignedRightShift.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.ir; - -import com.oracle.graal.graph.*; -import com.sun.cri.bytecode.*; -import com.sun.cri.ci.*; - - -public final class UnsignedRightShift extends Shift { - - /** - * @param opcode - * @param kind - * @param x - * @param y - * @param graph - */ - public UnsignedRightShift(CiKind kind, Value x, Value y, Graph graph) { - super(kind, kind == CiKind.Int ? Bytecodes.IUSHR : Bytecodes.LUSHR, x, y, graph); - } - - @Override - public String shortName() { - return ">>>"; - } - - @Override - public Node copy(Graph into) { - UnsignedRightShift x = new UnsignedRightShift(kind, null, null, graph()); - return x; - } - -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/Unwind.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/Unwind.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,86 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.ir; - -import com.oracle.graal.graph.*; -import com.sun.c1x.debug.*; -import com.sun.cri.ci.*; - -/** - * Unwind takes an exception object, destroys the current stack frame and passes the exception object to the system's exception dispatch code. - */ -public final class Unwind extends BlockEnd { - - private static final int INPUT_COUNT = 1; - private static final int INPUT_EXCEPTION = 0; - - private static final int SUCCESSOR_COUNT = 0; - - @Override - protected int inputCount() { - return super.inputCount() + INPUT_COUNT; - } - - @Override - protected int successorCount() { - return super.successorCount() + SUCCESSOR_COUNT; - } - - @Override - public Instruction next() { - return null; - } - - /** - * The instruction that produces the exception object. - */ - public Value exception() { - return (Value) inputs().get(super.inputCount() + INPUT_EXCEPTION); - } - - public Value setException(Value n) { - assert n == null || n.kind == CiKind.Object; - return (Value) inputs().set(super.inputCount() + INPUT_EXCEPTION, n); - } - - public Unwind(Value exception, Graph graph) { - super(CiKind.Object, 0, INPUT_COUNT, SUCCESSOR_COUNT, graph); - setException(exception); - } - - @Override - public void accept(ValueVisitor v) { - v.visitUnwind(this); - } - - @Override - public void print(LogStream out) { - out.print(kind.typeChar).print("unwind ").print(exception()); - } - - @Override - public Node copy(Graph into) { - Unwind x = new Unwind(null, into); - return x; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/Value.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/Value.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,210 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.ir; - -import java.util.*; - -import com.oracle.graal.graph.*; -import com.sun.c1x.debug.*; -import com.sun.cri.ci.*; -import com.sun.cri.ri.*; - -/** - * This class represents a value within the HIR graph, including local variables, phis, and - * all other instructions. - */ -public abstract class Value extends Node { - - /** - * The kind of this value. This is {@link CiKind#Void} for instructions that produce no value. - * This kind is guaranteed to be a {@linkplain CiKind#stackKind() stack kind}. - */ - public final CiKind kind; - - protected CiValue operand = CiValue.IllegalValue; - - /** - * Creates a new value with the specified kind. - * @param kind the type of this value - * @param inputCount - * @param successorCount - * @param graph - */ - public Value(CiKind kind, int inputCount, int successorCount, Graph graph) { - super(inputCount, successorCount, graph); - assert kind == kind.stackKind() : kind + " != " + kind.stackKind(); - this.kind = kind; - } - - /////////////// - // TODO: remove when Value class changes are completed - - @Override - protected Object clone() throws CloneNotSupportedException { - throw new CloneNotSupportedException(); - } - - /** - * Checks whether this value is a constant (i.e. it is of type {@link Constant}. - * @return {@code true} if this value is a constant - */ - public final boolean isConstant() { - return this instanceof Constant; - } - - /** - * Checks whether this value represents the null constant. - * @return {@code true} if this value represents the null constant - */ - public final boolean isNullConstant() { - return this instanceof Constant && ((Constant) this).value.isNull(); - } - - /** - * Convert this value to a constant if it is a constant, otherwise return null. - * @return the {@link CiConstant} represented by this value if it is a constant; {@code null} - * otherwise - */ - public final CiConstant asConstant() { - if (this instanceof Constant) { - return ((Constant) this).value; - } - return null; - } - - /** - * Gets the LIR operand associated with this instruction. - * @return the LIR operand for this instruction - */ - public final CiValue operand() { - return operand; - } - - /** - * Sets the LIR operand associated with this instruction. - * @param operand the operand to associate with this instruction - */ - public final void setOperand(CiValue operand) { - assert this.operand.isIllegal() : "operand cannot be set twice"; - assert operand != null && operand.isLegal() : "operand must be legal"; - assert operand.kind.stackKind() == this.kind; - this.operand = operand; - } - - /** - * Clears the LIR operand associated with this instruction. - */ - public final void clearOperand() { - this.operand = CiValue.IllegalValue; - } - - /** - * Computes the exact type of the result of this instruction, if possible. - * @return the exact type of the result of this instruction, if it is known; {@code null} otherwise - */ - public RiType exactType() { - return null; // default: unknown exact type - } - - /** - * Computes the declared type of the result of this instruction, if possible. - * @return the declared type of the result of this instruction, if it is known; {@code null} otherwise - */ - public RiType declaredType() { - return null; // default: unknown declared type - } - - /** - * Apply the specified closure to all the input values of this instruction. - * @param closure the closure to apply - */ - public void inputValuesDo(ValueClosure closure) { - for (int i = 0; i < inputs().size(); i++) { - inputs().set(i, closure.apply((Value) inputs().get(i))); - } - for (int i = 0; i < successors().size(); i++) { - successors().set(i, closure.apply((Value) successors().get(i))); - } - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("#"); - builder.append(id()); - builder.append(' '); - if (id() < 10) { - builder.append(' '); - } - builder.append(getClass().getSimpleName()); - builder.append(" [").append(flagsToString()).append("]"); - return builder.toString(); - } - - public String flagsToString() { - StringBuilder sb = new StringBuilder(); - return sb.toString(); - } - - /** - * Compute the value number of this Instruction. Local and global value numbering - * optimizations use a hash map, and the value number provides a hash code. - * If the instruction cannot be value numbered, then this method should return - * {@code 0}. - * @return the hashcode of this instruction - */ - public int valueNumber() { - return 0; - } - - /** - * Checks that this instruction is equal to another instruction for the purposes - * of value numbering. - * @param i the other instruction - * @return {@code true} if this instruction is equivalent to the specified - * instruction w.r.t. value numbering - */ - public boolean valueEqual(Node i) { - return false; - } - - /** - * This method supports the visitor pattern by accepting a visitor and calling the - * appropriate {@code visit()} method. - * - * @param v the visitor to accept - */ - public abstract void accept(ValueVisitor v); - - public abstract void print(LogStream out); - - @Override - public Map getDebugProperties() { - Map properties = super.getDebugProperties(); - properties.put("kind", kind.toString()); - properties.put("operand", operand == null ? "null" : operand.toString()); - return properties; - } - - -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/ValueAnchor.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/ValueAnchor.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,85 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.ir; - -import com.oracle.graal.graph.*; -import com.sun.c1x.debug.*; -import com.sun.cri.ci.*; - -/** - * The ValueAnchor instruction keeps non-CFG nodes above a certain point in the graph. - */ -public final class ValueAnchor extends Instruction { - - private static final int INPUT_COUNT = 1; - private static final int INPUT_OBJECT = 0; - - private static final int SUCCESSOR_COUNT = 0; - - @Override - protected int inputCount() { - return super.inputCount() + INPUT_COUNT; - } - - @Override - protected int successorCount() { - return super.successorCount() + SUCCESSOR_COUNT; - } - - /** - * The instruction that should be scheduled before this anchor. - */ - public Value object() { - return (Value) inputs().get(super.inputCount() + INPUT_OBJECT); - } - - public Value setObject(Value n) { - return (Value) inputs().set(super.inputCount() + INPUT_OBJECT, n); - } - - /** - * Constructs a new Anchor instruction. - * @param succ the successor block of the anchor - * @param graph - */ - public ValueAnchor(Value object, Graph graph) { - super(CiKind.Illegal, INPUT_COUNT, SUCCESSOR_COUNT, graph); - setObject(object); - } - - @Override - public void accept(ValueVisitor v) { - v.visitValueAnchor(this); - } - - @Override - public void print(LogStream out) { - out.print("value_anchor ").print(object()); - } - - @Override - public Node copy(Graph into) { - ValueAnchor x = new ValueAnchor(null, into); - return x; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/ValueClosure.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/ValueClosure.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.ir; - -/** - * The {@code ValueClosure} interface represents a first-class - * function that can be applied to a value. - */ -public interface ValueClosure { - Value apply(Value i); -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/ValueVisitor.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/ValueVisitor.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.ir; - -import com.sun.c1x.value.*; - -/** - * The {@link ValueVisitor} implements one half of the visitor - * pattern for {@linkplain Value IR values}, allowing clients to implement functionality - * depending on the type of an value without doing type tests. - */ -public abstract class ValueVisitor { - // Checkstyle: stop - public abstract void visitArithmetic(Arithmetic i); - public abstract void visitArrayLength(ArrayLength i); - public abstract void visitMerge(Merge i); - public abstract void visitCheckCast(CheckCast i); - public abstract void visitMaterialize(NormalizeCompare i); - public abstract void visitConstant(Constant i); - public abstract void visitConvert(Convert i); - public abstract void visitExceptionObject(ExceptionObject i); - public abstract void visitFrameState(FrameState i); - public abstract void visitAnchor(Anchor i); - public abstract void visitIf(If i); - public abstract void visitIfOp(Conditional i); - public abstract void visitInstanceOf(InstanceOf i); - public abstract void visitInvoke(Invoke i); - public abstract void visitLoadField(LoadField i); - public abstract void visitLoadIndexed(LoadIndexed i); - public abstract void visitLocal(Local i); - public abstract void visitLogic(Logic i); - public abstract void visitLookupSwitch(LookupSwitch i); - public abstract void visitMonitorAddress(MonitorAddress monitorAddress); - public abstract void visitMonitorEnter(MonitorEnter i); - public abstract void visitMonitorExit(MonitorExit i); - public abstract void visitNegate(Negate i); - public abstract void visitNewInstance(NewInstance i); - public abstract void visitNewMultiArray(NewMultiArray i); - public abstract void visitNewObjectArray(NewObjectArray i); - public abstract void visitNewTypeArray(NewTypeArray i); - public abstract void visitNullCheck(NullCheck i); - public abstract void visitPhi(Phi i); - public abstract void visitRegisterFinalizer(RegisterFinalizer i); - public abstract void visitReturn(Return i); - public abstract void visitShift(Shift i); - public abstract void visitStoreField(StoreField i); - public abstract void visitStoreIndexed(StoreIndexed i); - public abstract void visitTableSwitch(TableSwitch i); - public abstract void visitDeoptimize(Deoptimize deoptimize); - public abstract void visitExceptionDispatch(ExceptionDispatch exceptionDispatch); - public abstract void visitUnwind(Unwind unwind); - public abstract void visitLoopBegin(LoopBegin loopBegin); - public abstract void visitLoopEnd(LoopEnd loopEnd); - public abstract void visitValueAnchor(ValueAnchor valueAnchor); -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/Xor.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/Xor.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,111 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.ir; - -import com.oracle.graal.graph.*; -import com.oracle.max.graal.opt.CanonicalizerPhase.*; -import com.sun.cri.bytecode.*; -import com.sun.cri.ci.*; - -public final class Xor extends Logic { - private static final XorCanonicalizerOp CANONICALIZER = new XorCanonicalizerOp(); - - /** - * @param opcode - * @param kind - * @param x - * @param y - * @param graph - */ - public Xor(CiKind kind, Value x, Value y, Graph graph) { - super(kind, kind == CiKind.Int ? Bytecodes.IXOR : Bytecodes.LXOR, x, y, graph); - } - - @Override - public String shortName() { - return "^"; - } - - @Override - public Node copy(Graph into) { - Xor x = new Xor(kind, null, null, into); - return x; - } - - @SuppressWarnings("unchecked") - @Override - public T lookup(Class clazz) { - if (clazz == CanonicalizerOp.class) { - return (T) CANONICALIZER; - } - return super.lookup(clazz); - } - - private static class XorCanonicalizerOp implements CanonicalizerOp { - @Override - public Node canonical(Node node) { - assert node instanceof Xor; - Xor xor = (Xor) node; - CiKind kind = xor.kind; - Graph graph = xor.graph(); - Value x = xor.x(); - Value y = xor.y(); - if (x == y) { - if (kind == CiKind.Int) { - return Constant.forInt(0, graph); - } else { - assert kind == CiKind.Long; - return Constant.forLong(0L, graph); - } - } - if (x.isConstant() && !y.isConstant()) { - xor.swapOperands(); - Value t = y; - y = x; - x = t; - } - if (x.isConstant()) { - if (kind == CiKind.Int) { - return Constant.forInt(x.asConstant().asInt() ^ y.asConstant().asInt(), graph); - } else { - assert kind == CiKind.Long; - return Constant.forLong(x.asConstant().asLong() ^ y.asConstant().asLong(), graph); - } - } else if (y.isConstant()) { - if (kind == CiKind.Int) { - int c = y.asConstant().asInt(); - if (c == 0) { - return x; - } - } else { - assert kind == CiKind.Long; - long c = y.asConstant().asLong(); - if (c == 0) { - return x; - } - } - } - return xor; - } - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/package-info.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/ir/package-info.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2010, 2010, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/** - * High-level intermediate representation (HIR). - */ -package com.sun.c1x.ir; diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/lir/FrameMap.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/lir/FrameMap.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,395 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.lir; - -import static com.sun.cri.ci.CiCallingConvention.Type.*; -import static com.sun.cri.ci.CiKind.*; -import static java.lang.reflect.Modifier.*; - -import com.sun.c1x.*; -import com.sun.c1x.globalstub.*; -import com.sun.c1x.util.*; -import com.sun.cri.bytecode.*; -import com.sun.cri.ci.*; -import com.sun.cri.ci.CiCallingConvention.*; -import com.sun.cri.ri.*; -import com.sun.cri.util.*; - -/** - * This class is used to build the stack frame layout for a compiled method. - * - * This is the format of a stack frame on an x86 (i.e. IA32 or X64) platform: - *

- *   Base       Contents
- *
- *          :                                :
- *          | incoming overflow argument n   |
- *          |     ...                        |
- *          | incoming overflow argument 0   |
- *          | return address                 | Caller frame
- *   -------+--------------------------------+----------------  ---
- *          |                                |                   ^
- *          : callee save area               :                   |
- *          |                                |                   |
- *          +--------------------------------+                   |
- *          | alignment padding              |                   |
- *          +--------------------------------+                   |
- *          | ALLOCA block n                 |                   |
- *          :     ...                        :                   |
- *          | ALLOCA block 0                 | Current frame     |
- *          +--------------------------------+                   |
- *          | monitor n                      |                   |
- *          :     ...                        :                   |
- *          | monitor 0                      |                   |
- *          +--------------------------------+    ---            |
- *          | spill slot n                   |     ^           frame
- *          :     ...                        :     |           size
- *          | spill slot 0                   |  shared           |
- *          +- - - - - - - - - - - - - - - - +   slot            |
- *          | outgoing overflow argument n   |  indexes          |
- *          |     ...                        |     |             |
- *    %sp   | outgoing overflow argument 0   |     v             v
- *   -------+--------------------------------+----------------  ---
- *
- * 
- * Note that the size {@link Bytecodes#ALLOCA ALLOCA} blocks and {@code monitor}s in the frame may be greater - * than the size of a {@linkplain CiTarget#spillSlotSize spill slot}. - * - * @author Thomas Wuerthinger - * @author Ben L. Titzer - * @author Doug Simon - */ -public final class FrameMap { - - private final C1XCompilation compilation; - private final CiCallingConvention incomingArguments; - - /** - * Number of monitors used in this frame. - */ - private final int monitorCount; - - /** - * The final frame size. - * Value is only set after register allocation is complete. - */ - private int frameSize; - - /** - * The number of spill slots allocated by the register allocator. - * The value {@code -2} means that the size of outgoing argument stack slots - * is not yet fixed. The value {@code -1} means that the register - * allocator has started allocating spill slots and so the size of - * outgoing stack slots cannot change as outgoing stack slots and - * spill slots share the same slot index address space. - */ - private int spillSlotCount; - - /** - * The amount of memory allocated within the frame for uses of {@link Bytecodes#ALLOCA}. - */ - private int stackBlocksSize; - - /** - * Area occupied by outgoing overflow arguments. - * This value is adjusted as calling conventions for outgoing calls are retrieved. - */ - private int outgoingSize; - - /** - * Creates a new frame map for the specified method. - * - * @param compilation the compilation context - * @param method the outermost method being compiled - * @param monitors the number of monitors allocated on the stack for this method - */ - public FrameMap(C1XCompilation compilation, RiMethod method, int monitors) { - this.compilation = compilation; - this.frameSize = -1; - this.spillSlotCount = -2; - - assert monitors >= 0 : "not set"; - monitorCount = monitors; - if (method == null) { - incomingArguments = new CiCallingConvention(new CiValue[0], 0); - } else { - CiKind receiver = !isStatic(method.accessFlags()) ? method.holder().kind() : null; - incomingArguments = getCallingConvention(CRIUtil.signatureToKinds(method.signature(), receiver), JavaCallee); - } - } - - /** - * Gets the calling convention for a call with the specified signature. - * - * @param type the type of calling convention being requested - * @param signature the signature of the arguments - * @return a {@link CiCallingConvention} instance describing the location of parameters and the return value - */ - public CiCallingConvention getCallingConvention(CiKind[] signature, Type type) { - CiCallingConvention cc = compilation.registerConfig.getCallingConvention(type, signature, compilation.target); - if (type == RuntimeCall) { - assert cc.stackSize == 0 : "runtime call should not have stack arguments"; - } else if (type.out) { - assert frameSize == -1 : "frame size must not yet be fixed!"; - reserveOutgoing(cc.stackSize); - } - return cc; - } - - /** - * Gets the calling convention for the incoming arguments to the compiled method. - * @return the calling convention for incoming arguments - */ - public CiCallingConvention incomingArguments() { - return incomingArguments; - } - - /** - * Gets the frame size of the compiled frame. - * @return the size in bytes of the frame - */ - public int frameSize() { - assert this.frameSize != -1 : "frame size not computed yet"; - return frameSize; - } - - /** - * Sets the frame size for this frame. - * @param frameSize the frame size in bytes - */ - public void setFrameSize(int frameSize) { - assert this.frameSize == -1 : "should only be calculated once"; - this.frameSize = frameSize; - } - - /** - * Computes the frame size for this frame, given the number of spill slots. - * @param spillSlotCount the number of spill slots - */ - public void finalizeFrame(int spillSlotCount) { - assert this.spillSlotCount == -1 : "can only be set once"; - assert this.frameSize == -1 : "should only be calculated once"; - assert spillSlotCount >= 0 : "must be positive"; - - this.spillSlotCount = spillSlotCount; - int frameSize = offsetToStackBlocksEnd(); - frameSize += compilation.registerConfig.getCalleeSaveArea().size; - this.frameSize = compilation.target.alignFrameSize(frameSize); - } - - /** - * Informs the frame map that the compiled code uses a particular global stub, which - * may need stack space for outgoing arguments. - * - * @param stub the global stub - */ - public void usesGlobalStub(GlobalStub stub) { - reserveOutgoing(stub.argsSize); - } - - /** - * Converts a stack slot into a stack address. - * - * @param slot a stack slot - * @return a stack address - */ - public CiAddress toStackAddress(CiStackSlot slot) { - int size = compilation.target.sizeInBytes(slot.kind); - if (slot.inCallerFrame()) { - int offset = slot.index() * compilation.target.spillSlotSize + frameSize() + 8; - return new CiAddress(slot.kind, CiRegister.Frame.asValue(), offset); - } else { - int offset = offsetForOutgoingOrSpillSlot(slot.index(), size); - return new CiAddress(slot.kind, CiRegister.Frame.asValue(), offset); - } - } - - /** - * Gets the stack address within this frame for a given reserved stack block. - * - * @param stackBlock the value returned from {@link #reserveStackBlock(int)} identifying the stack block - * @return a representation of the stack location - */ - public CiAddress toStackAddress(StackBlock stackBlock) { - return new CiAddress(CiKind.Word, compilation.registerConfig.getFrameRegister().asValue(Word), offsetForStackBlock(stackBlock)); - } - - /** - * Converts the monitor index into the stack address of the object reference in the on-stack monitor. - * - * @param monitorIndex the monitor index - * @return a representation of the stack address - */ - public CiStackSlot toMonitorObjectStackAddress(int monitorIndex) { - int byteIndex = offsetForMonitorObject(monitorIndex); - assert byteIndex % compilation.target.wordSize == 0; - return CiStackSlot.get(CiKind.Object, byteIndex / compilation.target.wordSize); - } - - /** - * Converts the monitor index into the stack address of the on-stak monitor. - * - * @param monitorIndex the monitor index - * @return a representation of the stack address - */ - public CiStackSlot toMonitorBaseStackAddress(int monitorIndex) { - int byteIndex = offsetForMonitorBase(monitorIndex); - assert byteIndex % compilation.target.wordSize == 0; - return CiStackSlot.get(CiKind.Object, byteIndex / compilation.target.wordSize); - } - - /** - * Reserves space for stack-based outgoing arguments. - * - * @param argsSize the amount of space to reserve for stack-based outgoing arguments - */ - public void reserveOutgoing(int argsSize) { - assert spillSlotCount == -2 : "cannot reserve outgoing stack slot space once register allocation has started"; - if (argsSize > outgoingSize) { - outgoingSize = Util.roundUp(argsSize, compilation.target.spillSlotSize); - } - } - - /** - * Encapsulates the details of a stack block reserved by a call to {@link FrameMap#reserveStackBlock(int)}. - */ - public static final class StackBlock { - /** - * The size of this stack block. - */ - public final int size; - - /** - * The offset of this stack block within the frame space reserved for stack blocks. - */ - public final int offset; - - public StackBlock(int size, int offset) { - this.size = size; - this.offset = offset; - } - } - - /** - * Reserves a block of memory in the frame of the method being compiled. - * - * @param size the number of bytes to reserve - * @return a descriptor of the reserved block that can be used with {@link #toStackAddress(StackBlock)} once register - * allocation is complete and the size of the frame has been {@linkplain #finalizeFrame(int) finalized}. - */ - public StackBlock reserveStackBlock(int size) { - int wordSize = compilation.target.sizeInBytes(CiKind.Word); - assert (size % wordSize) == 0; - StackBlock block = new StackBlock(size, stackBlocksSize); - stackBlocksSize += size; - return block; - } - - private int offsetForStackBlock(StackBlock stackBlock) { - assert stackBlock.offset >= 0 && stackBlock.offset + stackBlock.size <= stackBlocksSize : "invalid stack block"; - int offset = offsetToStackBlocks() + stackBlock.offset; - assert offset <= (frameSize() - stackBlock.size) : "spill outside of frame"; - return offset; - } - - /** - * Gets the stack pointer offset for a outgoing stack argument or compiler spill slot. - * - * @param slotIndex the index of the stack slot within the slot index space reserved for - * @param size - * @return - */ - private int offsetForOutgoingOrSpillSlot(int slotIndex, int size) { - assert slotIndex >= 0 && slotIndex < (initialSpillSlot() + spillSlotCount) : "invalid spill slot"; - int offset = slotIndex * compilation.target.spillSlotSize; - assert offset <= (frameSize() - size) : "slot outside of frame"; - return offset; - } - - private int offsetForMonitorBase(int index) { - assert index >= 0 && index < monitorCount : "invalid monitor index : " + index + " (monitorCount=" + monitorCount + ")"; - int size = compilation.runtime.sizeOfBasicObjectLock(); - assert size != 0 : "monitors are not on the stack in this VM"; - int offset = offsetToMonitors() + index * size; - assert offset <= (frameSize() - size) : "monitor outside of frame"; - return offset; - } - - private int offsetToSpillArea() { - return outgoingSize; - } - - private int offsetToSpillEnd() { - return offsetToSpillArea() + spillSlotCount * compilation.target.spillSlotSize; - } - - private int offsetToMonitors() { - return offsetToCustomArea() + customAreaSize(); - } - - public int customAreaSize() { - return compilation.runtime.getCustomStackAreaSize(); - } - - public int offsetToCustomArea() { - return offsetToSpillEnd(); - } - - private int offsetToMonitorsEnd() { - return offsetToMonitors() + (monitorCount * compilation.runtime.sizeOfBasicObjectLock()); - } - - private int offsetToStackBlocks() { - return offsetToMonitorsEnd(); - } - - private int offsetToStackBlocksEnd() { - return offsetToStackBlocks() + stackBlocksSize; - } - - public int offsetToCalleeSaveAreaStart() { - return offsetToCalleeSaveAreaEnd() - compilation.registerConfig.getCalleeSaveArea().size; - } - - public int offsetToCalleeSaveAreaEnd() { - return frameSize; - } - - private int offsetForMonitorObject(int index) { - return offsetForMonitorBase(index) + compilation.runtime.basicObjectLockOffsetInBytes(); - } - - /** - * Gets the index of the first available spill slot relative to the base of the frame. - * After this call, no further outgoing stack slots can be {@linkplain #reserveOutgoing(int) reserved}. - * - * @return the index of the first available spill slot - */ - public int initialSpillSlot() { - if (spillSlotCount == -2) { - spillSlotCount = -1; - } - return outgoingSize / compilation.target.spillSlotSize; - } - -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/lir/LIRAssembler.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/lir/LIRAssembler.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,470 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.lir; - -import java.util.*; - -import com.oracle.max.asm.*; -import com.sun.c1x.*; -import com.sun.c1x.asm.*; -import com.sun.c1x.debug.*; -import com.sun.c1x.gen.*; -import com.sun.c1x.ir.*; -import com.sun.c1x.lir.FrameMap.*; -import com.sun.c1x.util.*; -import com.sun.cri.ci.*; -import com.sun.cri.ci.CiTargetMethod.*; -import com.sun.cri.ri.*; -import com.sun.cri.xir.CiXirAssembler.*; - -/** - * The {@code LIRAssembler} class definition. - */ -public abstract class LIRAssembler { - - public final C1XCompilation compilation; - public final TargetMethodAssembler tasm; - public final AbstractAssembler asm; - public final FrameMap frameMap; - public int registerRestoreEpilogueOffset = -1; - - protected final List xirSlowPath; - protected final List branchTargetBlocks; - - private int lastDecodeStart; - - protected static class SlowPath { - public final LIRXirInstruction instruction; - public final Label[] labels; - public final Map marks; - - public SlowPath(LIRXirInstruction instruction, Label[] labels, Map marks) { - this.instruction = instruction; - this.labels = labels; - this.marks = marks; - } - } - - public LIRAssembler(C1XCompilation compilation) { - this.compilation = compilation; - this.tasm = compilation.assembler(); - this.asm = tasm.asm; - this.frameMap = compilation.frameMap(); - this.branchTargetBlocks = new ArrayList(); - this.xirSlowPath = new ArrayList(); - } - - protected RiMethod method() { - return compilation.method; - } - - protected void addSlowPath(SlowPath sp) { - xirSlowPath.add(sp); - } - - public void emitLocalStubs() { - for (SlowPath sp : xirSlowPath) { - emitSlowPath(sp); - } - - // No more code may be emitted after this point - } - - protected int codePos() { - return asm.codeBuffer.position(); - } - - public abstract void emitTraps(); - - public void emitCode(List hir) { - if (C1XOptions.PrintLIR && !TTY.isSuppressed()) { - LIRList.printLIR(hir); - } - - for (LIRBlock b : hir) { - emitBlock(b); - } - - assert checkNoUnboundLabels(); - } - - void emitBlock(LIRBlock block) { - - block.setBlockEntryPco(codePos()); - - if (C1XOptions.PrintLIRWithAssembly) { - block.printWithoutPhis(TTY.out()); - } - - assert block.lir() != null : "must have LIR"; - if (C1XOptions.CommentedAssembly) { - String st = String.format(" block B%d", block.blockID()); - tasm.blockComment(st); - } - - emitLirList(block.lir()); - } - - void emitLirList(LIRList list) { - doPeephole(list); - - for (LIRInstruction op : list.instructionsList()) { - if (C1XOptions.CommentedAssembly) { - // Only print out branches - if (op.code == LIROpcode.Branch) { - tasm.blockComment(op.toStringWithIdPrefix()); - } - } - if (C1XOptions.PrintLIRWithAssembly && !TTY.isSuppressed()) { - // print out the LIR operation followed by the resulting assembly - TTY.println(op.toStringWithIdPrefix()); - TTY.println(); - } - - op.emitCode(this); - - if (C1XOptions.PrintLIRWithAssembly) { - printAssembly(asm); - } - } - } - - private void printAssembly(AbstractAssembler asm) { - byte[] currentBytes = asm.codeBuffer.copyData(lastDecodeStart, asm.codeBuffer.position()); - if (currentBytes.length > 0) { - String disasm = compilation.runtime.disassemble(currentBytes, lastDecodeStart); - if (disasm.length() != 0) { - TTY.println(disasm); - } else { - TTY.println("Code [+%d]: %d bytes", lastDecodeStart, currentBytes.length); - Util.printBytes(lastDecodeStart, currentBytes, C1XOptions.PrintAssemblyBytesPerLine); - } - } - lastDecodeStart = asm.codeBuffer.position(); - } - - boolean checkNoUnboundLabels() { - for (int i = 0; i < branchTargetBlocks.size() - 1; i++) { - if (!branchTargetBlocks.get(i).label().isBound()) { - TTY.println(String.format("label of block B%d is not bound", branchTargetBlocks.get(i).blockID())); - assert false : "unbound label"; - } - } - - return true; - } - - void emitCall(LIRCall op) { - verifyOopMap(op.info); - - switch (op.code) { - case DirectCall: - emitCallAlignment(op.code); - // fall through - case ConstDirectCall: - if (op.marks != null) { - op.marks.put(XirMark.CALLSITE, tasm.recordMark(null, new Mark[0])); - } - emitDirectCall(op.target, op.info); - break; - case IndirectCall: - emitCallAlignment(op.code); - if (op.marks != null) { - op.marks.put(XirMark.CALLSITE, tasm.recordMark(null, new Mark[0])); - } - emitIndirectCall(op.target, op.info, op.targetAddress()); - break; - case NativeCall: { - emitNativeCall((String) op.target, op.info, op.targetAddress()); - break; - } - case TemplateCall: { - emitTemplateCall(op.targetAddress()); - break; - } - default: - throw Util.shouldNotReachHere(); - } - } - - void emitOpLabel(LIRLabel op) { - asm.bind(op.label()); - } - - void emitOp1(LIROp1 op) { - switch (op.code) { - case Move: - if (op.moveKind() == LIROp1.LIRMoveKind.Volatile) { - emitVolatileMove(op.operand(), op.result(), op.kind, op.info); - } else { - moveOp(op.operand(), op.result(), op.kind, op.info, op.moveKind() == LIROp1.LIRMoveKind.Unaligned); - } - break; - case Prefetchr: - emitReadPrefetch(op.operand()); - break; - case Prefetchw: - emitReadPrefetch(op.operand()); - break; - case Return: - emitReturn(op.operand()); - break; - case Neg: - emitNegate((LIRNegate) op); - break; - case Lea: - emitLea(op.operand(), op.result()); - break; - case NullCheck: - emitNullCheck(op.operand(), op.info); - break; - case Lsb: - emitSignificantBitOp(false, op.operand(), op.result()); - break; - case Msb: - emitSignificantBitOp(true, op.operand(), op.result()); - break; - default: - throw Util.shouldNotReachHere(); - } - } - - public void emitOp0(LIROp0 op) { - switch (op.code) { - case Label: - throw Util.shouldNotReachHere(); - case Breakpoint: - emitBreakpoint(); - break; - default: - throw Util.shouldNotReachHere(); - } - } - - protected void emitOp2(LIROp2 op) { - switch (op.code) { - case Cmp: - emitCompare(op.condition(), op.operand1(), op.operand2(), op); - break; - - case Cmpl2i: - case Cmpfd2i: - case Ucmpfd2i: - emitCompare2Int(op.code, op.operand1(), op.operand2(), op.result(), op); - break; - - case Cmove: - emitConditionalMove(op.condition(), op.operand1(), op.operand2(), op.result()); - break; - - case Shl: - case Shr: - case Ushr: - if (op.operand2().isConstant()) { - emitShiftOp(op.code, op.operand1(), ((CiConstant) op.operand2()).asInt(), op.result()); - } else { - emitShiftOp(op.code, op.operand1(), op.operand2(), op.result(), op.tmp()); - } - break; - - case Add: - case Sub: - case Mul: - case Div: - case Rem: - emitArithOp(op.code, op.operand1(), op.operand2(), op.result(), op.info); - break; - - case Abs: - case Sqrt: - case Sin: - case Tan: - case Cos: - case Log: - case Log10: - emitIntrinsicOp(op.code, op.operand1(), op.operand2(), op.result(), op); - break; - - case LogicAnd: - case LogicOr: - case LogicXor: - emitLogicOp(op.code, op.operand1(), op.operand2(), op.result()); - break; - - default: - throw Util.shouldNotReachHere(); - } - } - - public void moveOp(CiValue src, CiValue dest, CiKind kind, LIRDebugInfo info, boolean unaligned) { - if (src.isRegister()) { - if (dest.isRegister()) { - assert info == null : "no patching and info allowed here"; - reg2reg(src, dest); - } else if (dest.isStackSlot()) { - assert info == null : "no patching and info allowed here"; - reg2stack(src, dest, kind); - } else if (dest.isAddress()) { - reg2mem(src, dest, kind, info, unaligned); - } else { - throw Util.shouldNotReachHere(); - } - - } else if (src.isStackSlot()) { - assert info == null : "no patching and info allowed here"; - if (dest.isRegister()) { - stack2reg(src, dest, kind); - } else if (dest.isStackSlot()) { - stack2stack(src, dest, kind); - } else { - throw Util.shouldNotReachHere(); - } - - } else if (src.isConstant()) { - if (dest.isRegister()) { - const2reg(src, dest, info); // patching is possible - } else if (dest.isStackSlot()) { - assert info == null : "no patching and info allowed here"; - const2stack(src, dest); - } else if (dest.isAddress()) { - const2mem(src, dest, kind, info); - } else { - throw Util.shouldNotReachHere(); - } - - } else if (src.isAddress()) { - if (dest.isStackSlot()) { - assert info == null && !unaligned; - mem2stack(src, dest, kind); - } else if (dest.isAddress()) { - assert info == null && !unaligned; - mem2mem(src, dest, kind); - } else { - mem2reg(src, dest, kind, info, unaligned); - } - - } else { - throw Util.shouldNotReachHere(src.toString() + ", dest=" + dest.toString() + ", " + kind); - } - } - - public void verifyOopMap(LIRDebugInfo info) { - if (C1XOptions.VerifyPointerMaps) { - // TODO: verify oops - Util.shouldNotReachHere(); - } - } - - protected abstract int initialFrameSizeInBytes(); - - protected abstract void doPeephole(LIRList list); - - protected abstract void emitSlowPath(SlowPath sp); - - public abstract void emitDeoptizationStub(LIRGenerator.DeoptimizationStub stub); - - protected abstract void emitAlignment(); - - protected abstract void emitBreakpoint(); - - protected abstract void emitLea(CiValue src, CiValue dst); - - protected abstract void emitNullCheck(CiValue src, LIRDebugInfo info); - - protected abstract void emitNegate(LIRNegate negate); - - protected abstract void emitMonitorAddress(int monitor, CiValue dst); - - protected abstract void emitStackAllocate(StackBlock src, CiValue dst); - - protected abstract void emitReturn(CiValue inOpr); - - protected abstract void emitReadPrefetch(CiValue inOpr); - - protected abstract void emitVolatileMove(CiValue inOpr, CiValue result, CiKind kind, LIRDebugInfo info); - - protected abstract void emitLogicOp(LIROpcode code, CiValue inOpr1, CiValue inOpr2, CiValue dst); - - protected abstract void emitIntrinsicOp(LIROpcode code, CiValue inOpr1, CiValue inOpr2, CiValue dst, LIROp2 op); - - protected abstract void emitArithOp(LIROpcode code, CiValue inOpr1, CiValue inOpr2, CiValue dst, LIRDebugInfo info); - - protected abstract void emitShiftOp(LIROpcode code, CiValue inOpr1, CiValue inOpr2, CiValue dst, CiValue tmpOpr); - - protected abstract void emitShiftOp(LIROpcode code, CiValue inOpr1, int asJint, CiValue dst); - - protected abstract void emitSignificantBitOp(boolean most, CiValue inOpr1, CiValue dst); - - protected abstract void emitConditionalMove(Condition condition, CiValue inOpr1, CiValue inOpr2, CiValue dst); - - protected abstract void emitCompare2Int(LIROpcode code, CiValue inOpr1, CiValue inOpr2, CiValue dst, LIROp2 op); - - protected abstract void emitCompare(Condition condition, CiValue inOpr1, CiValue inOpr2, LIROp2 op); - - protected abstract void emitBranch(LIRBranch branch); - - protected abstract void emitTableSwitch(LIRTableSwitch tableSwitch); - - protected abstract void emitConvert(LIRConvert convert); - - protected abstract void emitOp3(LIROp3 op3); - - protected abstract void emitCompareAndSwap(LIRCompareAndSwap compareAndSwap); - - protected abstract void emitXir(LIRXirInstruction xirInstruction); - - protected abstract void emitIndirectCall(Object target, LIRDebugInfo info, CiValue callAddress); - - protected abstract void emitDirectCall(Object target, LIRDebugInfo info); - - protected abstract void emitNativeCall(String symbol, LIRDebugInfo info, CiValue callAddress); - - protected abstract void emitTemplateCall(CiValue address); - - protected abstract void emitCallAlignment(LIROpcode code); - - protected abstract void emitMemoryBarriers(int barriers); - - protected abstract void reg2stack(CiValue src, CiValue dest, CiKind kind); - - protected abstract void reg2mem(CiValue src, CiValue dest, CiKind kind, LIRDebugInfo info, boolean unaligned); - - protected abstract void mem2reg(CiValue src, CiValue dest, CiKind kind, LIRDebugInfo info, boolean unaligned); - - protected abstract void const2mem(CiValue src, CiValue dest, CiKind kind, LIRDebugInfo info); - - protected abstract void const2stack(CiValue src, CiValue dest); - - protected abstract void const2reg(CiValue src, CiValue dest, LIRDebugInfo info); - - protected abstract void mem2stack(CiValue src, CiValue dest, CiKind kind); - - protected abstract void mem2mem(CiValue src, CiValue dest, CiKind kind); - - protected abstract void stack2stack(CiValue src, CiValue dest, CiKind kind); - - protected abstract void stack2reg(CiValue src, CiValue dest, CiKind kind); - - protected abstract void reg2reg(CiValue src, CiValue dest); - -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/lir/LIRBlock.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/lir/LIRBlock.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,259 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.lir; - -import java.util.*; - -import com.oracle.graal.graph.*; -import com.oracle.max.asm.*; -import com.sun.c1x.alloc.*; -import com.sun.c1x.debug.*; -import com.sun.c1x.util.*; -import com.sun.c1x.value.*; -import com.sun.cri.ci.*; - -/** - * The {@code LIRBlock} class definition. - */ -public final class LIRBlock { - - public final Label label = new Label(); - private LIRList lir; - private final int blockID; - private FrameState lastState; - private List instructions = new ArrayList(4); - private List predecessors = new ArrayList(4); - private List successors = new ArrayList(4); - - /** - * Bit map specifying which {@linkplain OperandPool operands} are live upon entry to this block. - * These are values used in this block or any of its successors where such value are not defined - * in this block. - * The bit index of an operand is its {@linkplain OperandPool#operandNumber(com.sun.cri.ci.CiValue) operand number}. - */ - public CiBitMap liveIn; - - /** - * Bit map specifying which {@linkplain OperandPool operands} are live upon exit from this block. - * These are values used in a successor block that are either defined in this block or were live - * upon entry to this block. - * The bit index of an operand is its {@linkplain OperandPool#operandNumber(com.sun.cri.ci.CiValue) operand number}. - */ - public CiBitMap liveOut; - - /** - * Bit map specifying which {@linkplain OperandPool operands} are used (before being defined) in this block. - * That is, these are the values that are live upon entry to the block. - * The bit index of an operand is its {@linkplain OperandPool#operandNumber(com.sun.cri.ci.CiValue) operand number}. - */ - public CiBitMap liveGen; - - /** - * Bit map specifying which {@linkplain OperandPool operands} are defined/overwritten in this block. - * The bit index of an operand is its {@linkplain OperandPool#operandNumber(com.sun.cri.ci.CiValue) operand number}. - */ - public CiBitMap liveKill; - - private int firstLirInstructionID; - private int lastLirInstructionID; - public int blockEntryPco; - - public LIRBlock(int blockID) { - this.blockID = blockID; - loopIndex = -1; - linearScanNumber = blockID; - } - - public List getInstructions() { - return instructions; - } - - public int firstLirInstructionId() { - return firstLirInstructionID; - } - - public void setFirstLirInstructionId(int firstLirInstructionId) { - this.firstLirInstructionID = firstLirInstructionId; - } - - public int lastLirInstructionId() { - return lastLirInstructionID; - } - - public void setLastLirInstructionId(int lastLirInstructionId) { - this.lastLirInstructionID = lastLirInstructionId; - } - - public int loopDepth; - - public LIRList lir() { - return lir; - } - - public void setLir(LIRList lir) { - this.lir = lir; - } - - public void setBlockEntryPco(int codePos) { - this.blockEntryPco = codePos; - } - - public void printWithoutPhis(LogStream out) { - out.println("LIR Block " + blockID()); - } - - public int blockID() { - return blockID; - } - - public int numberOfPreds() { - return predecessors.size(); - } - - public int numberOfSux() { - return successors.size(); - } - - public boolean isPredecessor(LIRBlock block) { - return predecessors.contains(block); - } - - public LIRBlock predAt(int i) { - return predecessors.get(i); - } - - public LIRBlock suxAt(int i) { - return successors.get(i); - } - - public List blockSuccessors() { - return successors; - } - - @Override - public String toString() { - return "B" + blockID(); - } - - public List blockPredecessors() { - return predecessors; - } - - public int loopDepth() { - // TODO(tw): Set correct loop depth. - return 0; - } - - public int loopIndex() { - return loopIndex; - } - - public void setLoopIndex(int v) { - loopIndex = v; - } - - public void setLoopDepth(int v) { - this.loopDepth = v; - } - - private int loopIndex; - - public Label label() { - return label; - } - - private int linearScanNumber = -1; - private boolean linearScanLoopEnd; - private boolean linearScanLoopHeader; - - public void setLinearScanNumber(int v) { - linearScanNumber = v; - } - - public int linearScanNumber() { - return linearScanNumber; - } - - public void setLinearScanLoopEnd() { - linearScanLoopEnd = true; - } - - public boolean isLinearScanLoopEnd() { - return linearScanLoopEnd; - } - - public void setLinearScanLoopHeader() { - this.linearScanLoopHeader = true; - } - - public boolean isLinearScanLoopHeader() { - return linearScanLoopHeader; - } - - public void replaceWith(LIRBlock other) { - for (LIRBlock pred : predecessors) { - Util.replaceAllInList(this, other, pred.successors); - } - for (int i = 0; i < other.predecessors.size(); ++i) { - if (other.predecessors.get(i) == this) { - other.predecessors.remove(i); - other.predecessors.addAll(i, this.predecessors); - } - } - successors.clear(); - predecessors.clear(); - } - - public void setInstructions(List list) { - instructions = list; - } - - public void setLastState(FrameState fs) { - lastState = fs; - } - - public FrameState lastState() { - return lastState; - } - - private Node first; - private Node last; - - public Node firstInstruction() { - return first; - } - - - public Node lastInstruction() { - return last; - } - - public void setFirstInstruction(Node n) { - first = n; - } - - - public void setLastInstruction(Node n) { - last = n; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/lir/LIRBranch.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/lir/LIRBranch.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,162 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.lir; - -import com.oracle.max.asm.*; -import com.sun.c1x.ir.*; -import com.sun.cri.ci.*; - -/** - * @author Marcelo Cintra - * @author Thomas Wuerthinger - * - */ -public class LIRBranch extends LIRInstruction { - - private Condition cond; - private CiKind kind; - private Label label; - - /** - * The target block of this branch. - */ - private LIRBlock block; - - /** - * This is the unordered block for a float branch. - */ - private LIRBlock unorderedBlock; - - - public LIRBranch(Condition cond, Label label) { - this(cond, label, null); - } - - /** - * Creates a new LIRBranch instruction. - * - * @param cond the branch condition - * @param label target label - * - */ - public LIRBranch(Condition cond, Label label, LIRDebugInfo info) { - super(LIROpcode.Branch, CiValue.IllegalValue, info, false); - this.cond = cond; - this.label = label; - } - - /** - * Creates a new LIRBranch instruction. - * - * @param cond - * @param kind - * @param block - * - */ - public LIRBranch(Condition cond, CiKind kind, LIRBlock block) { - super(LIROpcode.Branch, CiValue.IllegalValue, null, false); - this.cond = cond; - this.kind = kind; - this.label = block.label(); - this.block = block; - this.unorderedBlock = null; - } - - public LIRBranch(Condition cond, CiKind kind, LIRBlock block, LIRBlock ublock) { - super(LIROpcode.CondFloatBranch, CiValue.IllegalValue, null, false); - this.cond = cond; - this.kind = kind; - this.label = block.label(); - this.block = block; - this.unorderedBlock = ublock; - } - - /** - * @return the condition - */ - public Condition cond() { - return cond; - } - - public Label label() { - return label; - } - - public LIRBlock block() { - return block; - } - - public LIRBlock unorderedBlock() { - return unorderedBlock; - } - - public void changeBlock(LIRBlock b) { - assert block != null : "must have old block"; - assert block.label() == label() : "must be equal"; - - this.block = b; - this.label = b.label(); - } - - public void changeUblock(LIRBlock b) { - assert unorderedBlock != null : "must have old block"; - this.unorderedBlock = b; - } - - public void negateCondition() { - cond = cond.negate(); - } - - @Override - public void emitCode(LIRAssembler masm) { - masm.emitBranch(this); - } - - @Override - public String operationString(OperandFormatter operandFmt) { - StringBuilder buf = new StringBuilder(cond().operator).append(' '); - if (block() != null) { - buf.append("[B").append(block.blockID()).append(']'); - } else if (label().isBound()) { - buf.append("[label:0x").append(Integer.toHexString(label().position())).append(']'); - } else { - buf.append("[label:??]"); - } - if (unorderedBlock() != null) { - buf.append("unordered: [B").append(unorderedBlock().blockID()).append(']'); - } - return buf.toString(); - } - - public void substitute(LIRBlock oldBlock, LIRBlock newBlock) { - if (block == oldBlock) { - block = newBlock; - LIRInstruction instr = newBlock.lir().instructionsList().get(0); - assert instr instanceof LIRLabel : "first instruction of block must be label"; - label = ((LIRLabel) instr).label(); - } - if (unorderedBlock == oldBlock) { - unorderedBlock = newBlock; - } - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/lir/LIRCall.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/lir/LIRCall.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,143 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.lir; - -import java.util.*; - -import com.sun.cri.ci.*; -import com.sun.cri.ci.CiTargetMethod.*; -import com.sun.cri.ri.*; -import com.sun.cri.xir.CiXirAssembler.*; - -/** - * This class represents a call instruction; either to a {@linkplain CiRuntimeCall runtime method}, - * a {@linkplain RiMethod Java method}, a native function or a global stub. - * - * @author Marcelo Cintra - */ -public class LIRCall extends LIRInstruction { - - /** - * The target of the call. This will be a {@link CiRuntimeCall}, {@link RiMethod} or {@link CiValue} - * object denoting a call to the runtime, a Java method or a native function respectively. - */ - public final Object target; - /** - * The call site needs to be marked if this is non-null. - */ - public final Map marks; - - private final int targetAddressIndex; - - public final List pointerSlots; - - - private static CiValue[] toArray(List arguments) { - return arguments.toArray(new CiValue[arguments.size()]); - } - - public LIRCall(LIROpcode opcode, - Object target, - CiValue result, - List arguments, - LIRDebugInfo info, - Map marks, - boolean calleeSaved, - List pointerSlots) { - super(opcode, result, info, !calleeSaved, 0, 0, toArray(arguments)); - this.marks = marks; - this.pointerSlots = pointerSlots; - if (opcode == LIROpcode.DirectCall) { - this.targetAddressIndex = -1; - } else { - // The last argument is the operand holding the address for the indirect call - this.targetAddressIndex = arguments.size() - 1; - } - this.target = target; - } - - /** - * Emits target assembly code for this instruction. - * - * @param masm the target assembler - */ - @Override - public void emitCode(LIRAssembler masm) { - masm.emitCall(this); - } - - /** - * Returns the receiver for this method call. - * @return the receiver - */ - public CiValue receiver() { - return operand(0); - } - - public RiMethod method() { - return (RiMethod) target; - } - - public CiRuntimeCall runtimeCall() { - return (CiRuntimeCall) target; - } - - public CiValue targetAddress() { - if (targetAddressIndex >= 0) { - return operand(targetAddressIndex); - } - return null; - } - - @Override - public String operationString(OperandFormatter operandFmt) { - StringBuilder buf = new StringBuilder(); - if (result().isLegal()) { - buf.append(operandFmt.format(result())).append(" = "); - } - String targetAddress = null; - if (code == LIROpcode.RuntimeCall) { - buf.append(target); - } else if (code != LIROpcode.DirectCall && code != LIROpcode.ConstDirectCall) { - if (targetAddressIndex >= 0) { - targetAddress = operandFmt.format(targetAddress()); - buf.append(targetAddress); - } - } - buf.append('('); - boolean first = true; - for (LIROperand operandSlot : operands) { - String operand = operandFmt.format(operandSlot.value(this)); - if (!operand.isEmpty() && !operand.equals(targetAddress)) { - if (!first) { - buf.append(", "); - } else { - first = false; - } - buf.append(operand); - } - } - buf.append(')'); - return buf.toString(); - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/lir/LIRCompareAndSwap.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/lir/LIRCompareAndSwap.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,81 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.lir; - -import com.sun.cri.ci.*; - -/** - * The {@code LIRCompareAndSwap} class definition. - * - * @author Marcelo Cintra - * - */ -public class LIRCompareAndSwap extends LIRInstruction { - - /** - * Constructs a new LIRCompareAndSwap instruction. - * @param addr - * @param expectedValue - * @param newValue - */ - public LIRCompareAndSwap(LIROpcode opcode, CiValue addr, CiValue expectedValue, CiValue newValue) { - super(opcode, CiValue.IllegalValue, null, false, 0, 0, addr, expectedValue, newValue); - } - - /** - * Gets the address of compare and swap. - * - * @return the address - */ - public CiValue address() { - return operand(0); - } - - /** - * Gets the cmpValue of this class. - * - * @return the cmpValue - */ - public CiValue expectedValue() { - return operand(1); - } - - /** - * Gets the newValue of this class. - * - * @return the newValue - */ - public CiValue newValue() { - return operand(2); - } - - /** - * Emits target assembly code for this instruction. - * - * @param masm the target assembler - */ - @Override - public void emitCode(LIRAssembler masm) { - masm.emitCompareAndSwap(this); - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/lir/LIRConvert.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/lir/LIRConvert.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.lir; - -import com.sun.c1x.globalstub.*; -import com.sun.cri.bytecode.*; -import com.sun.cri.ci.*; - -/** - * The {@code LIRConvert} class definition. - * - * @author Marcelo Cintra - * - */ -public class LIRConvert extends LIROp1 { - - public final int bytecode; - public GlobalStub globalStub; - - /** - * Constructs a new instruction LIRConvert for a given operand. - * - * @param bytecode the opcode of the bytecode for this conversion - * @param operand the input operand for this instruction - * @param result the result operand for this instruction - */ - public LIRConvert(int bytecode, CiValue operand, CiValue result) { - super(LIROpcode.Convert, operand, result); - this.bytecode = bytecode; - } - - /** - * Emits target assembly code for this LIRConvert instruction. - * - * @param masm the LIRAssembler - */ - @Override - public void emitCode(LIRAssembler masm) { - masm.emitConvert(this); - } - - /** - * Prints this instruction to a LogStream. - */ - @Override - public String operationString(OperandFormatter operandFmt) { - return "[" + Bytecodes.nameOf(bytecode) + "] " + super.operationString(operandFmt); - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/lir/LIRDebugInfo.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/lir/LIRDebugInfo.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,109 +0,0 @@ -/* - * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.lir; - -import com.sun.c1x.*; -import com.sun.c1x.ir.*; -import com.sun.c1x.value.*; -import com.sun.cri.ci.*; - -/** - * This class represents debugging and deoptimization information attached to a LIR instruction. - */ -public class LIRDebugInfo { - - public abstract static class ValueLocator { - public abstract CiValue getLocation(Value value); - } - - public final FrameState state; - private LIRBlock exceptionEdge; - public CiDebugInfo debugInfo; - - public LIRDebugInfo(FrameState state) { - assert state != null; - this.state = state; - } - - public LIRBlock exceptionEdge() { - return exceptionEdge; - } - - public void setExceptionEdge(LIRBlock exceptionEdge) { - this.exceptionEdge = exceptionEdge; - } - - private LIRDebugInfo(LIRDebugInfo info) { - this.state = info.state; - this.exceptionEdge = info.exceptionEdge; - } - - public LIRDebugInfo copy() { - return new LIRDebugInfo(this); - } - - public void setOop(CiValue location, C1XCompilation compilation, CiBitMap frameRefMap, CiBitMap regRefMap) { - CiTarget target = compilation.target; - if (location.isAddress()) { - CiAddress stackLocation = (CiAddress) location; - assert stackLocation.index.isIllegal(); - if (stackLocation.base == CiRegister.Frame.asValue()) { - int offset = stackLocation.displacement; - assert offset % target.wordSize == 0 : "must be aligned"; - int stackMapIndex = offset / target.wordSize; - setBit(frameRefMap, stackMapIndex); - } - } else if (location.isStackSlot()) { - CiStackSlot stackSlot = (CiStackSlot) location; - assert !stackSlot.inCallerFrame(); - assert target.spillSlotSize == target.wordSize; - setBit(frameRefMap, stackSlot.index()); - } else { - assert location.isRegister() : "objects can only be in a register"; - CiRegisterValue registerLocation = (CiRegisterValue) location; - int reg = registerLocation.reg.number; - assert reg >= 0 : "object cannot be in non-object register " + registerLocation.reg; - assert reg < target.arch.registerReferenceMapBitCount; - setBit(regRefMap, reg); - } - } - - public CiDebugInfo debugInfo() { - assert debugInfo != null : "debug info not allocated yet"; - return debugInfo; - } - - public boolean hasDebugInfo() { - return debugInfo != null; - } - - public static void setBit(CiBitMap refMap, int bit) { - assert !refMap.get(bit) : "Ref map entry " + bit + " is already set."; - refMap.set(bit); - } - - @Override - public String toString() { - return state.toString(); - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/lir/LIRInstruction.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/lir/LIRInstruction.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,543 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.lir; - -import static com.sun.c1x.C1XCompilation.*; - -import java.util.*; - -import com.sun.c1x.*; -import com.sun.c1x.lir.LIROperand.*; -import com.sun.cri.ci.*; - -/** - * The {@code LIRInstruction} class definition. - * - * @author Marcelo Cintra - * @author Thomas Wuerthinger - */ -public abstract class LIRInstruction { - - private static final LIROperand ILLEGAL_SLOT = new LIROperand(CiValue.IllegalValue); - - private static final CiValue[] NO_OPERANDS = {}; - - public static final OperandMode[] OPERAND_MODES = OperandMode.values(); - - /** - * Constants denoting how a LIR instruction uses an operand. Any combination of these modes - * can be applied to an operand as long as every operand has at least one mode applied to it. - */ - public enum OperandMode { - /** - * An operand that is defined by a LIR instruction and is live after the code emitted for a LIR instruction. - */ - Output, - - /** - * An operand that is used by a LIR instruction and is live before the code emitted for a LIR instruction. - * Unless such an operand is also an output or temp operand, it must not be modified by a LIR instruction. - */ - Input, - - /** - * An operand that is both modified and used by a LIR instruction. - */ - Temp - } - - /** - * The opcode of this instruction. - */ - public final LIROpcode code; - - /** - * The result operand for this instruction. - */ - private final LIROperand result; - - /** - * The input and temporary operands of this instruction. - */ - protected final LIROperand[] operands; - - /** - * Used to emit debug information. - */ - public final LIRDebugInfo info; - - /** - * Value id for register allocation. - */ - public int id; - - /** - * Determines if all caller-saved registers are destroyed by this instruction. - */ - public final boolean hasCall; - - /** - * The number of variable or register output operands for this instruction. - * These operands are at indexes {@code [0 .. allocatorOutputCount-1]} in {@link #allocatorOperands}. - * - * @see OperandMode#Output - */ - private byte allocatorOutputCount; - - /** - * The number of variable or register input operands for this instruction. - * These operands are at indexes {@code [allocatorOutputCount .. (allocatorInputCount+allocatorOutputCount-1)]} in {@link #allocatorOperands}. - * - * @see OperandMode#Input - */ - private byte allocatorInputCount; - - /** - * The number of variable or register temp operands for this instruction. - * These operands are at indexes {@code [allocatorInputCount+allocatorOutputCount .. (allocatorTempCount+allocatorInputCount+allocatorOutputCount-1)]} in {@link #allocatorOperands}. - * - * @see OperandMode#Temp - */ - private byte allocatorTempCount; - - /** - * The number of variable or register input or temp operands for this instruction. - */ - private byte allocatorTempInputCount; - - /** - * The set of operands that must be known to the register allocator either to bind a register - * or stack slot to a {@linkplain CiVariable variable} or to inform the allocator about operands - * that are already fixed to a specific register. - * This set excludes all constant operands as well as operands that are bound to - * a stack slot in the {@linkplain CiStackSlot#inCallerFrame() caller's frame}. - * This array is partitioned as follows. - *
-     *
-     *   <-- allocatorOutputCount --> <-- allocatorInputCount --> <-- allocatorTempCount -->
-     *  +----------------------------+---------------------------+--------------------------+
-     *  |       output operands      |       input operands      |      temp operands       |
-     *  +----------------------------+---------------------------+--------------------------+
-     *
-     * 
- */ - final List allocatorOperands; - - /** - * Constructs a new LIR instruction that has no input or temp operands. - * - * @param opcode the opcode of the new instruction - * @param result the operand that holds the operation result of this instruction. This will be - * {@link CiValue#IllegalValue} for instructions that do not produce a result. - * @param info the {@link LIRDebugInfo} info that is to be preserved for the instruction. This will be {@code null} when no debug info is required for the instruction. - * @param hasCall specifies if all caller-saved registers are destroyed by this instruction - */ - public LIRInstruction(LIROpcode opcode, CiValue result, LIRDebugInfo info, boolean hasCall) { - this(opcode, result, info, hasCall, 0, 0, NO_OPERANDS); - } - - /** - * Constructs a new LIR instruction. The {@code operands} array is partitioned as follows: - *
-     *
-     *                              <------- tempInput -------> <--------- temp --------->
-     *  +--------------------------+---------------------------+--------------------------+
-     *  |       input operands     |   input+temp operands     |      temp operands       |
-     *  +--------------------------+---------------------------+--------------------------+
-     *
-     * 
- * - * @param opcode the opcode of the new instruction - * @param result the operand that holds the operation result of this instruction. This will be - * {@link CiValue#IllegalValue} for instructions that do not produce a result. - * @param info the {@link LIRDebugInfo} that is to be preserved for the instruction. This will be {@code null} when no debug info is required for the instruction. - * @param hasCall specifies if all caller-saved registers are destroyed by this instruction - * @param tempInput the number of operands that are both {@linkplain OperandMode#Input input} and {@link OperandMode#Temp temp} operands for this instruction - * @param temp the number of operands that are {@link OperandMode#Temp temp} operands for this instruction - * @param operands the input and temp operands for the instruction - */ - public LIRInstruction(LIROpcode opcode, CiValue result, LIRDebugInfo info, boolean hasCall, int tempInput, int temp, CiValue... operands) { - this.code = opcode; - this.info = info; - this.hasCall = hasCall; - - assert opcode != LIROpcode.Move || result != CiValue.IllegalValue; - allocatorOperands = new ArrayList(operands.length + 3); - this.result = initOutput(result); - - C1XMetrics.LIRInstructions++; - - if (opcode == LIROpcode.Move) { - C1XMetrics.LIRMoveInstructions++; - } - id = -1; - this.operands = new LIROperand[operands.length]; - initInputsAndTemps(tempInput, temp, operands); - - assert verifyOperands(); - } - - private LIROperand initOutput(CiValue output) { - assert output != null; - if (output != CiValue.IllegalValue) { - if (output.isAddress()) { - return addAddress((CiAddress) output); - } - if (output.isStackSlot()) { - return new LIROperand(output); - } - - assert allocatorOperands.size() == allocatorOutputCount; - allocatorOperands.add(output); - allocatorOutputCount++; - return new LIRVariableOperand(allocatorOperands.size() - 1); - } else { - return ILLEGAL_SLOT; - } - } - - /** - * Adds a {@linkplain CiValue#isLegal() legal} value that is part of an address to - * the list of {@linkplain #allocatorOperands register allocator operands}. If - * the value is {@linkplain CiVariable variable}, then its index into the list - * of register allocator operands is returned. Otherwise, {@code -1} is returned. - */ - private int addAddressPart(CiValue part) { - if (part.isRegister()) { - allocatorInputCount++; - allocatorOperands.add(part); - return -1; - } - if (part.isVariable()) { - allocatorInputCount++; - allocatorOperands.add(part); - return allocatorOperands.size() - 1; - } - assert part.isIllegal(); - return -1; - } - - private LIROperand addAddress(CiAddress address) { - assert address.base.isVariableOrRegister(); - - int base = addAddressPart(address.base); - int index = addAddressPart(address.index); - - if (base != -1 || index != -1) { - return new LIRAddressOperand(base, index, address); - } - - assert address.base.isRegister() && (address.index.isIllegal() || address.index.isRegister()); - return new LIROperand(address); - } - - private LIROperand addOperand(CiValue operand, boolean isInput, boolean isTemp) { - assert operand != null; - if (operand != CiValue.IllegalValue) { - assert !(operand.isAddress()); - if (operand.isStackSlot()) { - // no variables to add - return new LIROperand(operand); - } else if (operand.isConstant()) { - // no variables to add - return new LIROperand(operand); - } else { - assert allocatorOperands.size() == allocatorOutputCount + allocatorInputCount + allocatorTempInputCount + allocatorTempCount; - allocatorOperands.add(operand); - - if (isInput && isTemp) { - allocatorTempInputCount++; - } else if (isInput) { - allocatorInputCount++; - } else { - assert isTemp; - allocatorTempCount++; - } - - return new LIRVariableOperand(allocatorOperands.size() - 1); - } - } else { - return ILLEGAL_SLOT; - } - } - - /** - * Gets an input or temp operand of this instruction. - * - * @param index the index of the operand requested - * @return the {@code index}'th operand - */ - public final CiValue operand(int index) { - if (index >= operands.length) { - return CiValue.IllegalValue; - } - - return operands[index].value(this); - } - - private void initInputsAndTemps(int tempInputCount, int tempCount, CiValue[] operands) { - - // Addresses in instruction - for (int i = 0; i < operands.length; i++) { - CiValue op = operands[i]; - if (op.isAddress()) { - this.operands[i] = addAddress((CiAddress) op); - } - } - - int z = 0; - // Input-only operands - for (int i = 0; i < operands.length - tempInputCount - tempCount; i++) { - if (this.operands[z] == null) { - this.operands[z] = addOperand(operands[z], true, false); - } - z++; - } - - // Operands that are both inputs and temps - for (int i = 0; i < tempInputCount; i++) { - if (this.operands[z] == null) { - this.operands[z] = addOperand(operands[z], true, true); - } - z++; - } - - // Temp-only operands - for (int i = 0; i < tempCount; i++) { - if (this.operands[z] == null) { - this.operands[z] = addOperand(operands[z], false, true); - } - z++; - } - } - - private boolean verifyOperands() { - for (LIROperand operandSlot : operands) { - assert operandSlot != null; - } - - for (CiValue operand : this.allocatorOperands) { - assert operand != null; - assert operand.isVariableOrRegister() : "LIR operands can only be variables and registers initially, not " + operand.getClass().getSimpleName(); - } - return true; - } - - /** - * Gets the result operand for this instruction. - * - * @return return the result operand - */ - public final CiValue result() { - return result.value(this); - } - - /** - * Gets the instruction name. - * - * @return the name of the enum constant that represents the instruction opcode, exactly as declared in the enum - * LIROpcode declaration. - */ - public String name() { - return code.name(); - } - - /** - * Abstract method to be used to emit target code for this instruction. - * - * @param masm the target assembler. - */ - public abstract void emitCode(LIRAssembler masm); - - /** - * Utility for specializing how a {@linkplain CiValue LIR operand} is formatted to a string. - * The {@linkplain OperandFormatter#DEFAULT default formatter} returns the value of - * {@link CiValue#toString()}. - */ - public static class OperandFormatter { - public static final OperandFormatter DEFAULT = new OperandFormatter(); - - /** - * Formats a given operand as a string. - * - * @param operand the operand to format - * @return {@code operand} as a string - */ - public String format(CiValue operand) { - return operand.toString(); - } - } - - /** - * Gets the operation performed by this instruction in terms of its operands as a string. - */ - public String operationString(OperandFormatter operandFmt) { - StringBuilder buf = new StringBuilder(); - if (result != ILLEGAL_SLOT) { - buf.append(operandFmt.format(result.value(this))).append(" = "); - } - if (operands.length > 1) { - buf.append("("); - } - boolean first = true; - for (LIROperand operandSlot : operands) { - String operand = operandFmt.format(operandSlot.value(this)); - if (!operand.isEmpty()) { - if (!first) { - buf.append(", "); - } else { - first = false; - } - buf.append(operand); - } - } - if (operands.length > 1) { - buf.append(")"); - } - return buf.toString(); - } - - public boolean verify() { - return true; - } - - /** - * Determines if a given opcode is in a given range of valid opcodes. - * - * @param opcode the opcode to be tested. - * @param start the lower bound range limit of valid opcodes - * @param end the upper bound range limit of valid opcodes - */ - protected static boolean isInRange(LIROpcode opcode, LIROpcode start, LIROpcode end) { - return start.ordinal() < opcode.ordinal() && opcode.ordinal() < end.ordinal(); - } - - public boolean hasOperands() { - if (info != null || hasCall) { - return true; - } - return allocatorOperands.size() > 0; - } - - public final int operandCount(OperandMode mode) { - if (mode == OperandMode.Output) { - return allocatorOutputCount; - } else if (mode == OperandMode.Input) { - return allocatorInputCount + allocatorTempInputCount; - } else { - assert mode == OperandMode.Temp; - return allocatorTempInputCount + allocatorTempCount; - } - } - - public final CiValue operandAt(OperandMode mode, int index) { - if (mode == OperandMode.Output) { - assert index < allocatorOutputCount; - return allocatorOperands.get(index); - } else if (mode == OperandMode.Input) { - assert index < allocatorInputCount + allocatorTempInputCount; - return allocatorOperands.get(index + allocatorOutputCount); - } else { - assert mode == OperandMode.Temp; - assert index < allocatorTempInputCount + allocatorTempCount; - return allocatorOperands.get(index + allocatorOutputCount + allocatorInputCount); - } - } - - public final void setOperandAt(OperandMode mode, int index, CiValue location) { - assert index < operandCount(mode); - assert location.kind != CiKind.Illegal; - assert operandAt(mode, index).isVariable(); - if (mode == OperandMode.Output) { - assert index < allocatorOutputCount; - allocatorOperands.set(index, location); - } else if (mode == OperandMode.Input) { - assert index < allocatorInputCount + allocatorTempInputCount; - allocatorOperands.set(index + allocatorOutputCount, location); - } else { - assert mode == OperandMode.Temp; - assert index < allocatorTempInputCount + allocatorTempCount; - allocatorOperands.set(index + allocatorOutputCount + allocatorInputCount, location); - } - } - - public final LIRBlock exceptionEdge() { - return (info == null) ? null : info.exceptionEdge(); - } - - @Override - public String toString() { - return toString(OperandFormatter.DEFAULT); - } - - public final String toStringWithIdPrefix() { - if (id != -1) { - return String.format("%4d %s", id, toString()); - } - return " " + toString(); - } - - protected static String refMapToString(CiDebugInfo debugInfo, OperandFormatter operandFmt) { - StringBuilder buf = new StringBuilder(); - if (debugInfo.hasStackRefMap()) { - CiBitMap bm = debugInfo.frameRefMap; - for (int slot = bm.nextSetBit(0); slot >= 0; slot = bm.nextSetBit(slot + 1)) { - if (buf.length() != 0) { - buf.append(", "); - } - buf.append(operandFmt.format(CiStackSlot.get(CiKind.Object, slot))); - } - } - if (debugInfo.hasRegisterRefMap()) { - CiBitMap bm = debugInfo.registerRefMap; - for (int reg = bm.nextSetBit(0); reg >= 0; reg = bm.nextSetBit(reg + 1)) { - if (buf.length() != 0) { - buf.append(", "); - } - CiRegisterValue register = compilation().target.arch.registers[reg].asValue(CiKind.Object); - buf.append(operandFmt.format(register)); - } - } - return buf.toString(); - } - - protected void appendDebugInfo(StringBuilder buf, OperandFormatter operandFmt, LIRDebugInfo info) { - if (info != null) { - buf.append(" [bci:").append(info.state.bci); - if (info.hasDebugInfo()) { - CiDebugInfo debugInfo = info.debugInfo(); - String refmap = refMapToString(debugInfo, operandFmt); - if (refmap.length() != 0) { - buf.append(", refmap(").append(refmap.trim()).append(')'); - } - } - buf.append(']'); - } - } - - public String toString(OperandFormatter operandFmt) { - StringBuilder buf = new StringBuilder(name()).append(' ').append(operationString(operandFmt)); - appendDebugInfo(buf, operandFmt, info); - return buf.toString(); - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/lir/LIRLabel.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/lir/LIRLabel.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.lir; - -import com.oracle.max.asm.*; -import com.sun.cri.ci.*; - -/** - * The {@code LIRLabel} class definition. - * - * @author Marcelo Cintra - */ -public class LIRLabel extends LIROp0 { - - private Label label; - - /** - * Constructs a LIRLabel instruction. - * @param label the label - */ - public LIRLabel(Label label) { - super(LIROpcode.Label, CiValue.IllegalValue, null); - assert label != null; - this.label = label; - } - - /** - * Gets the label associated to this instruction. - * @return the label - */ - public Label label() { - return label; - } - - /** - * Emits target assembly code for this LIRLabel instruction. - * @param masm the LIRAssembler - */ - @Override - public void emitCode(LIRAssembler masm) { - masm.emitOpLabel(this); - } - - /** - * Prints this instruction to a LogStream. - */ - @Override - public String operationString(OperandFormatter operandFmt) { - return label.isBound() ? String.valueOf(label.position()) : "?"; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/lir/LIRList.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/lir/LIRList.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,480 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.lir; - -import java.util.*; - -import com.oracle.max.asm.*; -import com.sun.c1x.*; -import com.sun.c1x.alloc.*; -import com.sun.c1x.debug.*; -import com.sun.c1x.gen.*; -import com.sun.c1x.globalstub.*; -import com.sun.c1x.ir.*; -import com.sun.cri.ci.*; -import com.sun.cri.ci.CiTargetMethod.*; -import com.sun.cri.ri.*; -import com.sun.cri.xir.*; -import com.sun.cri.xir.CiXirAssembler.*; - -/** - * This class represents a list of LIR instructions and contains factory methods for creating and appending LIR - * instructions to this list. - */ -public final class LIRList { - - private List operations; - private final LIRGenerator generator; - - private final LIROpcode runtimeCallOp; - - private LIROpcode directCallOp(RiMethod method) { - return C1XOptions.UseConstDirectCall && method.hasCompiledCode() ? LIROpcode.ConstDirectCall : LIROpcode.DirectCall; - } - - public LIRList(LIRGenerator generator) { - this.generator = generator; - this.operations = new ArrayList(8); - runtimeCallOp = C1XOptions.UseConstDirectCall ? LIROpcode.ConstDirectCall : LIROpcode.DirectCall; - } - - private void append(LIRInstruction op) { - if (C1XOptions.PrintIRWithLIR && !TTY.isSuppressed()) { - generator.maybePrintCurrentInstruction(); - TTY.println(op.toStringWithIdPrefix()); - TTY.println(); - } - operations.add(op); - assert op.verify(); - } - - public List instructionsList() { - return operations; - } - - public int length() { - return operations.size(); - } - - public LIRInstruction at(int i) { - return operations.get(i); - } - - public void callDirect(RiMethod method, CiValue result, List arguments, LIRDebugInfo info, Map marks, List pointerSlots) { - append(new LIRCall(directCallOp(method), method, result, arguments, info, marks, false, pointerSlots)); - } - - public void callIndirect(RiMethod method, CiValue result, List arguments, LIRDebugInfo info, Map marks, List pointerSlots) { - append(new LIRCall(LIROpcode.IndirectCall, method, result, arguments, info, marks, false, pointerSlots)); - } - - public void callNative(String symbol, CiValue result, List arguments, LIRDebugInfo info, Map marks) { - append(new LIRCall(LIROpcode.NativeCall, symbol, result, arguments, info, marks, false, null)); - } - - public void templateCall(CiValue result, List arguments) { - append(new LIRCall(LIROpcode.TemplateCall, null, result, arguments, null, null, false, null)); - } - - public void membar(int barriers) { - append(new LIRMemoryBarrier(barriers)); - } - - public void branchDestination(Label lbl) { - append(new LIRLabel(lbl)); - } - - public void negate(CiValue src, CiValue dst, GlobalStub globalStub) { - LIRNegate op = new LIRNegate(src, dst); - op.globalStub = globalStub; - append(op); - } - - public void lea(CiValue src, CiValue dst) { - append(new LIROp1(LIROpcode.Lea, src, dst)); - } - - public void unalignedMove(CiValue src, CiValue dst) { - append(new LIROp1(LIROp1.LIRMoveKind.Unaligned, src, dst, dst.kind, null)); - } - - public void move(CiAddress src, CiValue dst, LIRDebugInfo info) { - append(new LIROp1(LIROpcode.Move, src, dst, src.kind, info)); - } - - public void move(CiValue src, CiAddress dst, LIRDebugInfo info) { - append(new LIROp1(LIROpcode.Move, src, dst, dst.kind, info)); - } - - public void move(CiValue src, CiValue dst, CiKind kind) { - append(new LIROp1(LIROpcode.Move, src, dst, kind, null)); - } - - public void move(CiValue src, CiValue dst) { - append(new LIROp1(LIROpcode.Move, src, dst, dst.kind, null)); - } - - public void volatileMove(CiValue src, CiValue dst, CiKind kind, LIRDebugInfo info) { - append(new LIROp1(LIROp1.LIRMoveKind.Volatile, src, dst, kind, info)); - } - - public void oop2reg(Object o, CiValue reg) { - append(new LIROp1(LIROpcode.Move, CiConstant.forObject(o), reg)); - } - - public void returnOp(CiValue result) { - append(new LIROp1(LIROpcode.Return, result)); - } - - public void monitorAddress(int monitor, CiValue dst) { - append(new LIRMonitorAddress(dst, monitor)); - } - - public void convert(int code, CiValue left, CiValue dst, GlobalStub globalStub) { - LIRConvert op = new LIRConvert(code, left, dst); - op.globalStub = globalStub; - append(op); - } - - public void logicalAnd(CiValue left, CiValue right, CiValue dst) { - append(new LIROp2(LIROpcode.LogicAnd, left, right, dst)); - } - - public void logicalOr(CiValue left, CiValue right, CiValue dst) { - append(new LIROp2(LIROpcode.LogicOr, left, right, dst)); - } - - public void logicalXor(CiValue left, CiValue right, CiValue dst) { - append(new LIROp2(LIROpcode.LogicXor, left, right, dst)); - } - - public void nullCheck(CiValue opr, LIRDebugInfo info) { - append(new LIROp1(LIROpcode.NullCheck, opr, info)); - } - - public void compareTo(CiValue left, CiValue right, CiValue dst) { - append(new LIROp2(LIROpcode.CompareTo, left, right, dst)); - } - - public void cmp(Condition condition, CiValue left, CiValue right, LIRDebugInfo info) { - append(new LIROp2(LIROpcode.Cmp, condition, left, right, info)); - } - - public void cmp(Condition condition, CiValue left, CiValue right) { - cmp(condition, left, right, null); - } - - public void cmp(Condition condition, CiValue left, int right, LIRDebugInfo info) { - cmp(condition, left, CiConstant.forInt(right), info); - } - - public void cmp(Condition condition, CiValue left, int right) { - cmp(condition, left, right, null); - } - - public void cmove(Condition condition, CiValue src1, CiValue src2, CiValue dst) { - append(new LIROp2(LIROpcode.Cmove, condition, src1, src2, dst)); - } - - public void abs(CiValue from, CiValue to, CiValue tmp) { - append(new LIROp2(LIROpcode.Abs, from, tmp, to)); - } - - public void sqrt(CiValue from, CiValue to, CiValue tmp) { - append(new LIROp2(LIROpcode.Sqrt, from, tmp, to)); - } - - public void log(CiValue from, CiValue to, CiValue tmp) { - append(new LIROp2(LIROpcode.Log, from, tmp, to)); - } - - public void log10(CiValue from, CiValue to, CiValue tmp) { - append(new LIROp2(LIROpcode.Log10, from, tmp, to)); - } - - public void sin(CiValue from, CiValue to, CiValue tmp1, CiValue tmp2) { - append(new LIROp2(LIROpcode.Sin, from, tmp1, to, tmp2)); - } - - public void cos(CiValue from, CiValue to, CiValue tmp1, CiValue tmp2) { - append(new LIROp2(LIROpcode.Cos, from, tmp1, to, tmp2)); - } - - public void tan(CiValue from, CiValue to, CiValue tmp1, CiValue tmp2) { - append(new LIROp2(LIROpcode.Tan, from, tmp1, to, tmp2)); - } - - public void add(CiValue left, CiValue right, CiValue res) { - append(new LIROp2(LIROpcode.Add, left, right, res)); - } - - public void sub(CiValue left, CiValue right, CiValue res) { - append(new LIROp2(LIROpcode.Sub, left, right, res)); - } - - public void mul(CiValue left, CiValue right, CiValue res) { - append(new LIROp2(LIROpcode.Mul, left, right, res)); - } - - public void div(CiValue left, CiValue right, CiValue res, LIRDebugInfo info) { - append(new LIROp2(LIROpcode.Div, left, right, res, info)); - } - - public void rem(CiValue left, CiValue right, CiValue res, LIRDebugInfo info) { - append(new LIROp2(LIROpcode.Rem, left, right, res, info)); - } - - public void jump(LIRBlock block) { - append(new LIRBranch(Condition.TRUE, CiKind.Illegal, block)); - } - - public void branch(Condition cond, Label lbl) { - append(new LIRBranch(cond, lbl)); - } - - public void branch(Condition cond, Label lbl, LIRDebugInfo info) { - append(new LIRBranch(cond, lbl, info)); - } - - public void branch(Condition cond, CiKind kind, LIRBlock block) { - assert kind != CiKind.Float && kind != CiKind.Double : "no fp comparisons"; - append(new LIRBranch(cond, kind, block)); - } - - public void branch(Condition cond, CiKind kind, LIRBlock block, LIRBlock unordered) { - assert kind == CiKind.Float || kind == CiKind.Double : "fp comparisons only"; - append(new LIRBranch(cond, kind, block, unordered)); - } - - public void tableswitch(CiValue index, int lowKey, LIRBlock defaultTargets, LIRBlock[] targets) { - append(new LIRTableSwitch(index, lowKey, defaultTargets, targets)); - } - - public void shiftLeft(CiValue value, int count, CiValue dst) { - shiftLeft(value, CiConstant.forInt(count), dst, CiValue.IllegalValue); - } - - public void shiftRight(CiValue value, int count, CiValue dst) { - shiftRight(value, CiConstant.forInt(count), dst, CiValue.IllegalValue); - } - - public void lcmp2int(CiValue left, CiValue right, CiValue dst) { - append(new LIROp2(LIROpcode.Cmpl2i, left, right, dst)); - } - - public void callRuntime(CiRuntimeCall rtCall, CiValue result, List arguments, LIRDebugInfo info) { - append(new LIRCall(runtimeCallOp, rtCall, result, arguments, info, null, false, null)); - } - - public void breakpoint() { - append(new LIROp0(LIROpcode.Breakpoint)); - } - - public void prefetch(CiAddress addr, boolean isStore) { - append(new LIROp1(isStore ? LIROpcode.Prefetchw : LIROpcode.Prefetchr, addr)); - } - - public void idiv(CiValue left, CiValue right, CiValue res, CiValue tmp, LIRDebugInfo info) { - append(new LIROp3(LIROpcode.Idiv, left, right, tmp, res, info)); - } - - public void irem(CiValue left, CiValue right, CiValue res, CiValue tmp, LIRDebugInfo info) { - append(new LIROp3(LIROpcode.Irem, left, right, tmp, res, info)); - } - - public void ldiv(CiValue left, CiValue right, CiValue res, CiValue tmp, LIRDebugInfo info) { - append(new LIROp3(LIROpcode.Ldiv, left, right, tmp, res, info)); - } - - public void lrem(CiValue left, CiValue right, CiValue res, CiValue tmp, LIRDebugInfo info) { - append(new LIROp3(LIROpcode.Lrem, left, right, tmp, res, info)); - } - - public void lsb(CiValue src, CiValue dst) { - append(new LIRSignificantBit(LIROpcode.Lsb, src, dst)); - } - - public void msb(CiValue src, CiValue dst) { - append(new LIRSignificantBit(LIROpcode.Msb, src, dst)); - } - - public void wdiv(CiValue left, CiValue right, CiValue res, CiValue tmp, LIRDebugInfo info) { - append(new LIROp3(LIROpcode.Wdiv, left, right, tmp, res, info)); - } - - public void wrem(CiValue left, CiValue right, CiValue res, CiValue tmp, LIRDebugInfo info) { - append(new LIROp3(LIROpcode.Wrem, left, right, tmp, res, info)); - } - - public void wdivi(CiValue left, CiValue right, CiValue res, CiValue tmp, LIRDebugInfo info) { - append(new LIROp3(LIROpcode.Wdivi, left, right, tmp, res, info)); - } - - public void wremi(CiValue left, CiValue right, CiValue res, CiValue tmp, LIRDebugInfo info) { - append(new LIROp3(LIROpcode.Wremi, left, right, tmp, res, info)); - } - - public void cmpMemInt(Condition condition, CiValue base, int disp, int c, LIRDebugInfo info) { - append(new LIROp2(LIROpcode.Cmp, condition, new CiAddress(CiKind.Int, base, disp), CiConstant.forInt(c), info)); - } - - public void cmpRegMem(Condition condition, CiValue reg, CiAddress addr, LIRDebugInfo info) { - append(new LIROp2(LIROpcode.Cmp, condition, reg, addr, info)); - } - - public void shiftLeft(CiValue value, CiValue count, CiValue dst, CiValue tmp) { - append(new LIROp2(LIROpcode.Shl, value, count, dst, tmp)); - } - - public void shiftRight(CiValue value, CiValue count, CiValue dst, CiValue tmp) { - append(new LIROp2(LIROpcode.Shr, value, count, dst, tmp)); - } - - public void unsignedShiftRight(CiValue value, CiValue count, CiValue dst, CiValue tmp) { - append(new LIROp2(LIROpcode.Ushr, value, count, dst, tmp)); - } - - public void fcmp2int(CiValue left, CiValue right, CiValue dst, boolean isUnorderedLess) { - append(new LIROp2(isUnorderedLess ? LIROpcode.Ucmpfd2i : LIROpcode.Cmpfd2i, left, right, dst)); - } - - public void casLong(CiValue addr, CiValue cmpValue, CiValue newValue) { - // Compare and swap produces condition code "zero" if contentsOf(addr) == cmpValue, - // implying successful swap of newValue into addr - append(new LIRCompareAndSwap(LIROpcode.CasLong, addr, cmpValue, newValue)); - } - - public void casObj(CiValue addr, CiValue cmpValue, CiValue newValue) { - // Compare and swap produces condition code "zero" if contentsOf(addr) == cmpValue, - // implying successful swap of newValue into addr - append(new LIRCompareAndSwap(LIROpcode.CasObj, addr, cmpValue, newValue)); - } - - public void casInt(CiValue addr, CiValue cmpValue, CiValue newValue) { - // Compare and swap produces condition code "zero" if contentsOf(addr) == cmpValue, - // implying successful swap of newValue into addr - append(new LIRCompareAndSwap(LIROpcode.CasInt, addr, cmpValue, newValue)); - } - - public void store(CiValue src, CiAddress dst, LIRDebugInfo info) { - append(new LIROp1(LIROpcode.Move, src, dst, dst.kind, info)); - } - - public void load(CiAddress src, CiValue dst, LIRDebugInfo info) { - append(new LIROp1(LIROpcode.Move, src, dst, src.kind, info)); - } - - public static void printBlock(LIRBlock x) { - // print block id - TTY.print("B%d ", x.blockID()); - - // print flags - if (x.isLinearScanLoopHeader()) { - TTY.print("lh "); - } - if (x.isLinearScanLoopEnd()) { - TTY.print("le "); - } - - // print block bci range - TTY.print("[%d, %d] ", -1, -1); - - // print predecessors and successors - if (x.numberOfPreds() > 0) { - TTY.print("preds: "); - for (int i = 0; i < x.numberOfPreds(); i++) { - TTY.print("B%d ", x.predAt(i).blockID()); - } - } - - if (x.numberOfSux() > 0) { - TTY.print("sux: "); - for (int i = 0; i < x.numberOfSux(); i++) { - TTY.print("B%d ", x.suxAt(i).blockID()); - } - } - - TTY.println(); - } - - public static void printLIR(List blocks) { - if (TTY.isSuppressed()) { - return; - } - TTY.println("LIR:"); - int i; - for (i = 0; i < blocks.size(); i++) { - LIRBlock bb = blocks.get(i); - printBlock(bb); - TTY.println("__id_Instruction___________________________________________"); - bb.lir().printInstructions(); - } - } - - private void printInstructions() { - for (int i = 0; i < operations.size(); i++) { - TTY.println(operations.get(i).toStringWithIdPrefix()); - TTY.println(); - } - TTY.println(); - } - - public void append(LIRInsertionBuffer buffer) { - assert this == buffer.lirList() : "wrong lir list"; - int n = operations.size(); - - if (buffer.numberOfOps() > 0) { - // increase size of instructions list - for (int i = 0; i < buffer.numberOfOps(); i++) { - operations.add(null); - } - // insert ops from buffer into instructions list - int opIndex = buffer.numberOfOps() - 1; - int ipIndex = buffer.numberOfInsertionPoints() - 1; - int fromIndex = n - 1; - int toIndex = operations.size() - 1; - for (; ipIndex >= 0; ipIndex--) { - int index = buffer.indexAt(ipIndex); - // make room after insertion point - while (index < fromIndex) { - operations.set(toIndex--, operations.get(fromIndex--)); - } - // insert ops from buffer - for (int i = buffer.countAt(ipIndex); i > 0; i--) { - operations.set(toIndex--, buffer.opAt(opIndex--)); - } - } - } - - buffer.finish(); - } - - public void insertBefore(int i, LIRInstruction op) { - operations.add(i, op); - } - - public void xir(XirSnippet snippet, CiValue[] operands, CiValue outputOperand, int tempInputCount, int tempCount, CiValue[] inputOperands, int[] operandIndices, int outputOperandIndex, - LIRDebugInfo info, LIRDebugInfo infoAfter, RiMethod method, List pointerSlots) { - append(new LIRXirInstruction(snippet, operands, outputOperand, tempInputCount, tempCount, inputOperands, operandIndices, outputOperandIndex, info, infoAfter, method, pointerSlots)); - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/lir/LIRMemoryBarrier.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/lir/LIRMemoryBarrier.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2010, 2010, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.lir; - -import com.sun.cri.bytecode.Bytecodes.*; -import com.sun.cri.ci.*; - -/** - * LIR instruction implementing a {@linkplain MemoryBarriers memory barrier}. - * - * @author Doug Simon - */ -public class LIRMemoryBarrier extends LIRInstruction { - - public final int barriers; - - public LIRMemoryBarrier(int barriers) { - super(LIROpcode.Membar, CiValue.IllegalValue, null, false); - this.barriers = barriers; - } - - @Override - public void emitCode(LIRAssembler masm) { - masm.emitMemoryBarriers(barriers); - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/lir/LIRMonitorAddress.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/lir/LIRMonitorAddress.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2010, 2010, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.lir; - -import com.sun.cri.ci.*; - -/** - * LIR instruction used in to represent the address of a monitor object within the stack frame. - * - * @author Doug Simon - */ -public class LIRMonitorAddress extends LIRInstruction { - - public final int monitor; - - public LIRMonitorAddress(CiValue result, int monitor) { - super(LIROpcode.MonitorAddress, result, null, false); - this.monitor = monitor; - } - - @Override - public void emitCode(LIRAssembler masm) { - masm.emitMonitorAddress(monitor, this.result()); - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/lir/LIRNegate.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/lir/LIRNegate.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2010, 2010, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.lir; - -import com.sun.c1x.globalstub.*; -import com.sun.cri.ci.*; - -/** - * The {@code LIRNegate} class definition. - * - * @author Thomas Wuerthinger - * - */ -public class LIRNegate extends LIROp1 { - - public GlobalStub globalStub; - - /** - * Constructs a new instruction LIRNegate for a given operand. - * - * @param operand the input operand for this instruction - * @param result the result operand for this instruction - */ - public LIRNegate(CiValue operand, CiValue result) { - super(LIROpcode.Neg, operand, result); - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/lir/LIROp0.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/lir/LIROp0.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,74 +0,0 @@ -/* - * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.lir; - -import com.sun.cri.ci.*; - -/** - * The {@code LIROp0} class definition. - * - * @author Marcelo Cintra - * - */ -public class LIROp0 extends LIRInstruction { - - /** - * Creates a LIROp0 instruction. - * - * @param opcode the opcode of the new instruction - */ - public LIROp0(LIROpcode opcode) { - this(opcode, CiValue.IllegalValue); - } - - /** - * Creates a LIROp0 instruction. - * - * @param opcode the opcode of the new instruction - * @param result the result operand to the new instruction - */ - public LIROp0(LIROpcode opcode, CiValue result) { - this(opcode, result, null); - } - - /** - * Creates a LIROp0 instruction. - * - * @param opcode the opcode of the new instruction - * @param result the result operand to the new instruction - * @param info used to emit debug information associated to this instruction - */ - public LIROp0(LIROpcode opcode, CiValue result, LIRDebugInfo info) { - super(opcode, result, info, false); - assert isInRange(opcode, LIROpcode.BeginOp0, LIROpcode.EndOp0) : "Opcode " + opcode + " is invalid for a LIROP0 instruction"; - } - - /** - * Emit assembly code for this instruction. - * @param masm the target assembler - */ - @Override - public void emitCode(LIRAssembler masm) { - masm.emitOp0(this); - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/lir/LIROp1.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/lir/LIROp1.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,177 +0,0 @@ -/* - * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.lir; - -import com.sun.c1x.util.*; -import com.sun.cri.ci.*; - -/** - * The {@code LIROp1} class definition. The LIROp1 instruction has only one input operand. - * - * @author Marcelo Cintra - */ -public class LIROp1 extends LIRInstruction { - - public enum LIRMoveKind { - Normal, Volatile, Unaligned - } - - public final CiKind kind; // the operand type - public final LIRMoveKind moveKind; // flag that indicate the kind of move - - /** - * Constructs a new LIROp1 instruction. - * - * @param opcode the instruction's opcode - * @param opr the first input operand - * @param result the operand that holds the result of this instruction - * @param kind the kind of this instruction - * @param info the object holding information needed to emit debug information - */ - public LIROp1(LIROpcode opcode, CiValue opr, CiValue result, CiKind kind, LIRDebugInfo info) { - super(opcode, result, info, false, 0, 0, opr); - this.kind = kind; - this.moveKind = LIRMoveKind.Normal; - assert isInRange(opcode, LIROpcode.BeginOp1, LIROpcode.EndOp1) : "The " + opcode + " is not a valid LIROp1 opcode"; - } - - /** - * Constructs a new LIROp1 instruction. - * - * @param opcode the instruction's opcode - * @param opr the first input operand - * @param result the operand that holds the result of this instruction - * @param kind the kind of this instruction - */ - public LIROp1(LIROpcode opcode, CiValue opr, CiValue result, CiKind kind) { - this(opcode, opr, result, kind, null); - } - - /** - * Constructs a new LIROp1 instruction. - * - * @param opcode the instruction's opcode - * @param opr the first input operand - * @param result the operand that holds the result of this instruction - */ - public LIROp1(LIROpcode opcode, CiValue opr, CiValue result) { - this(opcode, opr, result, CiKind.Illegal); - } - - /** - * Constructs a new LIROp1 instruction. - * - * @param opcode the instruction's opcode - * @param opr the first input operand - */ - public LIROp1(LIROpcode opcode, CiValue opr) { - this(opcode, opr, CiValue.IllegalValue); - } - - /** - * Constructs a new LIROp1 instruction. - * - * @param moveKind the kind of move the instruction represents - * @param operand the single input operand - * @param result the operand that holds the result of this instruction - * @param kind the kind of this instruction - * @param info the object holding information needed to emit debug information - */ - public LIROp1(LIRMoveKind moveKind, CiValue operand, CiValue result, CiKind kind, LIRDebugInfo info) { - super(LIROpcode.Move, result, info, false, 0, 0, operand); - this.kind = kind; - this.moveKind = moveKind; - } - - /** - * Constructs a new LIROp1 instruction. - * - * @param opcode the instruction's opcode - * @param opr the first input operand - * @param info the object holding information needed to emit debug information - */ - public LIROp1(LIROpcode opcode, CiValue opr, LIRDebugInfo info) { - super(opcode, CiValue.IllegalValue, info, false, 0, 0, opr); - this.kind = CiKind.Illegal; - this.moveKind = LIRMoveKind.Normal; - assert isInRange(opcode, LIROpcode.BeginOp1, LIROpcode.EndOp1) : "The " + opcode + " is not a valid LIROp1 opcode"; - } - - /** - * Gets the input operand of this instruction. - * - * @return opr the input operand. - */ - public CiValue operand() { - return operand(0); - } - - /** - * Gets the kind of move of this instruction. - * - * @return flags the constant that represents the move kind. - */ - public LIRMoveKind moveKind() { - assert code == LIROpcode.Move : "The opcode must be of type LIROpcode.Move in LIROp1"; - return moveKind; - } - - @Override - public void emitCode(LIRAssembler masm) { - masm.emitOp1(this); - } - - @Override - public String name() { - if (code == LIROpcode.Move) { - switch (moveKind()) { - case Normal: - return "move"; - case Unaligned: - return "unaligned move"; - case Volatile: - return "volatile_move"; - default: - throw Util.shouldNotReachHere(); - } - } else { - return super.name(); - } - } - - @Override - public boolean verify() { - switch (code) { - case Move: - assert (operand().isLegal()) && (result().isLegal()) : "Operand and result must be valid in a LIROp1 move instruction."; - break; - case NullCheck: - assert operand().isVariableOrRegister() : "Operand must be a register in a LIROp1 null check instruction."; - break; - case Return: - assert operand().isVariableOrRegister() || operand().isIllegal() : "Operand must be (register | illegal) in a LIROp1 return instruction."; - break; - } - return true; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/lir/LIROp2.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/lir/LIROp2.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,184 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.lir; - -import com.sun.c1x.ir.*; -import com.sun.cri.ci.*; - -/** - * The {@code LIROp2} class represents a LIR instruction that performs an operation on two operands. - * - * @author Marcelo Cintra - * @author Thomas Wuerthinger - * @author Ben L. Titzer - */ -public class LIROp2 extends LIRInstruction { - - final Condition condition; - - /** - * Constructs a new LIROp2 instruction. - * - * @param opcode the instruction's opcode - * @param condition the instruction's condition - * @param opr1 the first input operand - * @param opr2 the second input operand - * @param info the object holding information needed to emit debug information - */ - public LIROp2(LIROpcode opcode, Condition condition, CiValue opr1, CiValue opr2, LIRDebugInfo info) { - super(opcode, CiValue.IllegalValue, info, false, 0, 0, opr1, opr2); - this.condition = condition; - assert opcode == LIROpcode.Cmp : "Instruction opcode should be of type LIROpcode.Cmp"; - } - - /** - * Constructs a new LIROp2 instruction. - * - * @param opcode the instruction's opcode - * @param condition the instruction's condition - * @param opr1 the first input operand - * @param opr2 the second input operand - * @param result the operand that holds the result of this instruction - */ - public LIROp2(LIROpcode opcode, Condition condition, CiValue opr1, CiValue opr2, CiValue result) { - super(opcode, result, null, false, 0, 0, opr1, opr2); - this.condition = condition; - assert opcode == LIROpcode.Cmove : "Instruction opcode should be of type LIROpcode.Cmove"; - } - - /** - * Constructs a new LIROp2 instruction. - * - * @param opcode the instruction's opcode - * @param opr1 the first input operand - * @param opr2 the second input operand - * @param result the operand that holds the result of this instruction - * @param info the object holding information needed to emit debug information - * @param kind the kind of this instruction - */ - public LIROp2(LIROpcode opcode, CiValue opr1, CiValue opr2, CiValue result, LIRDebugInfo info, CiKind kind, boolean hasCall) { - super(opcode, result, info, hasCall, 0, 0, opr1, opr2); - this.condition = null; - assert opcode != LIROpcode.Cmp && isInRange(opcode, LIROpcode.BeginOp2, LIROpcode.EndOp2) : "The " + opcode + " is not a valid LIROp2 opcode"; - } - - /** - * Constructs a new LIROp2 instruction. - * - * @param opcode the instruction's opcode - * @param opr1 the instruction's first operand - * @param opr2 the instruction's second operand - * @param result the operand that holds the result of this instruction - * @param info the object holding information needed to emit debug information - */ - public LIROp2(LIROpcode opcode, CiValue opr1, CiValue opr2, CiValue result, LIRDebugInfo info) { - this(opcode, opr1, opr2, result, info, CiKind.Illegal, false); - } - - /** - * Constructs a new LIROp2 instruction. - * - * @param opcode the instruction's opcode - * @param opr1 the instruction's first operand - * @param opr2 the instruction's second operand - * @param result the operand that holds the result of this instruction - */ - public LIROp2(LIROpcode opcode, CiValue opr1, CiValue opr2, CiValue result) { - this(opcode, opr1, opr2, result, (LIRDebugInfo) null); - } - - /** - * Constructs a new LIROp2 instruction. - * - * @param opcode the instruction's opcode - * @param opr1 the first input operand - * @param opr2 the second input operand - * @param result the operand that holds the result of this instruction - * @param tmp the temporary operand used by this instruction - */ - public LIROp2(LIROpcode opcode, CiValue opr1, CiValue opr2, CiValue result, CiValue tmp) { - super(opcode, result, null, false, 0, 1, opr1, opr2, tmp); - this.condition = null; - assert opcode != LIROpcode.Cmp && isInRange(opcode, LIROpcode.BeginOp2, LIROpcode.EndOp2) : "The " + opcode + " is not a valid LIROp2 opcode"; - } - - /** - * Gets the first input operand. - * - * @return opr1 the first input operand - */ - public CiValue operand1() { - return operand(0); - } - - /** - * Gets the second input operand. - * - * @return opr2 the second input operand - */ - public CiValue operand2() { - return operand(1); - } - - /** - * Gets the temporary operand of this instruction. - * - * @return tmp the temporary operand of this instruction - * - */ - public CiValue tmp() { - return operand(2); - } - - /** - * Gets the condition of this instruction, if it is a Cmp or Cmove LIR instruction. - * - * @return condition the condition of this instruction - */ - public Condition condition() { - assert code == LIROpcode.Cmp || code == LIROpcode.Cmove : "Field access only valid for cmp and cmove"; - return condition; - } - - /** - * Emit target assembly code for this instruction. - * - * @param masm the target assembler - */ - @Override - public void emitCode(LIRAssembler masm) { - masm.emitOp2(this); - } - - /** - * Prints this instruction. - */ - @Override - public String operationString(OperandFormatter operandFmt) { - if (code == LIROpcode.Cmove) { - return condition.toString() + " " + super.operationString(operandFmt); - } - return super.operationString(operandFmt); - } -} - diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/lir/LIROp3.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/lir/LIROp3.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,78 +0,0 @@ -/* - * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.lir; - -import com.sun.cri.ci.*; - -/** - * The {@code LIROp3} class definition. - * - * @author Marcelo Cintra - * - */ -public class LIROp3 extends LIRInstruction { - - /** - * Creates a new LIROp3 instruction. A LIROp3 instruction represents a LIR instruction - * that has three input operands. - * - * @param opcode the instruction's opcode - * @param opr1 the first input operand - * @param opr2 the second input operand - * @param opr3 the third input operand - * @param result the result operand - * @param info the debug information, used for deoptimization, associated to this instruction - */ - public LIROp3(LIROpcode opcode, CiValue opr1, CiValue opr2, CiValue opr3, CiValue result, LIRDebugInfo info) { - super(opcode, result, info, false, 1, 1, opr1, opr2, opr3); - assert isInRange(opcode, LIROpcode.BeginOp3, LIROpcode.EndOp3) : "The " + opcode + " is not a valid LIROp3 opcode"; - } - - /** - * Gets the opr1 of this class. - * - * @return the opr1 - */ - public CiValue opr1() { - return operand(0); - } - - /** - * Gets the opr2 of this class. - * - * @return the opr2 - */ - public CiValue opr2() { - return operand(1); - } - - /** - * Emits assembly code for this instruction. - * - * @param masm the target assembler - */ - @Override - public void emitCode(LIRAssembler masm) { - masm.emitOp3(this); - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/lir/LIROpcode.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/lir/LIROpcode.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,107 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.lir; - -/** - * The {@code LirOpcode} enum represents the Operation code of each LIR instruction. - * - * @author Marcelo Cintra - * @author Thomas Wuerthinger - */ -public enum LIROpcode { - // Checkstyle: stop - // @formatter:off - BeginOp0, - Label, - Breakpoint, - RuntimeCall, - Membar, - Branch, - CondFloatBranch, - EndOp0, - BeginOp1, - NullCheck, - Return, - Lea, - Neg, - TableSwitch, - Move, - Prefetchr, - Prefetchw, - Convert, - Lsb, - Msb, - MonitorAddress, - EndOp1, - BeginOp2, - Cmp, - Cmpl2i, - Ucmpfd2i, - Cmpfd2i, - Cmove, - Add, - Sub, - Mul, - Div, - Rem, - Sqrt, - Abs, - Sin, - Cos, - Tan, - Log, - Log10, - LogicAnd, - LogicOr, - LogicXor, - Shl, - Shr, - Ushr, - CompareTo, - EndOp2, - BeginOp3, - Idiv, - Irem, - Ldiv, - Lrem, - Wdiv, - Wdivi, - Wrem, - Wremi, - EndOp3, - NativeCall, - DirectCall, - ConstDirectCall, - IndirectCall, - TemplateCall, - InstanceOf, - CheckCast, - StoreCheck, - CasLong, - CasWord, - CasObj, - CasInt, - Xir, - // @formatter:on - // Checkstyle: resume -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/lir/LIROperand.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/lir/LIROperand.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,134 +0,0 @@ -/* - * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.lir; - -import com.sun.cri.ci.*; - -/** - * An instruction operand. If the register allocator can modify this operand (e.g. to replace a - * variable with a register), then it will have a corresponding entry in the {@link LIRInstruction#allocatorOperands} - * list of an instruction. - * - * @author Doug Simon - */ -public class LIROperand { - - /** - * The value of the operand. - */ - CiValue value; - - LIROperand(CiValue value) { - this.value = value; - } - - /** - * Gets the value of this operand. This may still be a {@linkplain CiVariable} - * if the register allocator has not yet assigned a register or stack address to the operand. - * - * @param inst the instruction containing this operand - */ - public CiValue value(LIRInstruction inst) { - return value; - } - - @Override - public String toString() { - return value.toString(); - } - - static class LIRVariableOperand extends LIROperand { - /** - * Index into an instruction's {@linkplain LIRInstruction#allocatorOperands allocator operands}. - */ - final int index; - - LIRVariableOperand(int index) { - super(null); - this.index = index; - } - - @Override - public CiValue value(LIRInstruction inst) { - if (value == null) { - CiValue value = inst.allocatorOperands.get(index); - if (value.isVariable()) { - return value; - } - this.value = value; - } - return value; - } - - @Override - public String toString() { - if (value == null) { - return "operands[" + index + "]"; - } - return value.toString(); - } - } - - /** - * An address operand with at least one {@linkplain CiVariable variable} constituent. - */ - static class LIRAddressOperand extends LIROperand { - int base; - int index; - - LIRAddressOperand(int base, int index, CiAddress address) { - super(address); - assert base != -1 || index != -1 : "address should have at least one variable part"; - this.base = base; - this.index = index; - } - - @Override - public CiValue value(LIRInstruction inst) { - if (base != -1 || index != -1) { - CiAddress address = (CiAddress) value; - CiValue baseOperand = base == -1 ? address.base : inst.allocatorOperands.get(base); - CiValue indexOperand = index == -1 ? address.index : inst.allocatorOperands.get(index); - if (address.index.isLegal()) { - assert indexOperand.isVariableOrRegister(); - if (baseOperand.isVariable() || indexOperand.isVariable()) { - return address; - } - } else { - if (baseOperand.isVariable()) { - return address; - } - } - value = new CiAddress(address.kind, baseOperand, indexOperand, address.scale, address.displacement); - base = -1; - index = -1; - } - return value; - } - - @Override - public String toString() { - return value.toString(); - } - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/lir/LIRSignificantBit.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/lir/LIRSignificantBit.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2010, 2010, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.lir; - -import com.sun.cri.bytecode.*; -import com.sun.cri.ci.*; - -/** - * LIR instruction used in translating {@link Bytecodes#LSB} and {@link Bytecodes#MSB}. - * - * @author Doug Simon - */ -public class LIRSignificantBit extends LIRInstruction { - - public LIRSignificantBit(LIROpcode opcode, CiValue operand, CiValue result) { - super(opcode, result, null, false, 1, 0, operand); - } - - @Override - public void emitCode(LIRAssembler masm) { - masm.emitSignificantBitOp(code == LIROpcode.Msb, operand(0), result()); - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/lir/LIRTableSwitch.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/lir/LIRTableSwitch.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,89 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.lir; - -import com.sun.cri.ci.*; - -/** - * @author Doug Simon - */ -public class LIRTableSwitch extends LIRInstruction { - - public LIRBlock defaultTarget; - - public final LIRBlock[] targets; - - public final int lowKey; - - public LIRTableSwitch(CiValue value, int lowKey, LIRBlock defaultTarget, LIRBlock[] targets) { - super(LIROpcode.TableSwitch, CiValue.IllegalValue, null, false, 1, 0, value); - this.lowKey = lowKey; - this.targets = targets; - this.defaultTarget = defaultTarget; - } - - @Override - public void emitCode(LIRAssembler masm) { - masm.emitTableSwitch(this); - } - - /** - * @return the input value to this switch - */ - public CiValue value() { - return operand(0); - } - - @Override - public String operationString(OperandFormatter operandFmt) { - StringBuilder buf = new StringBuilder(super.operationString(operandFmt)); - buf.append("\ndefault: [B").append(defaultTarget.blockID()).append(']'); - int key = lowKey; - for (LIRBlock b : targets) { - buf.append("\ncase ").append(key).append(": [B").append(b.blockID()).append(']'); - key++; - } - return buf.toString(); - } - - - private LIRBlock substitute(LIRBlock block, LIRBlock oldBlock, LIRBlock newBlock) { - if (block == oldBlock) { - LIRInstruction instr = newBlock.lir().instructionsList().get(0); - assert instr instanceof LIRLabel : "first instruction of block must be label"; - return newBlock; - } - return oldBlock; - } - - public void substitute(LIRBlock oldBlock, LIRBlock newBlock) { - if (substitute(defaultTarget, oldBlock, newBlock) == newBlock) { - defaultTarget = newBlock; - } - for (int i = 0; i < targets.length; i++) { - if (substitute(targets[i], oldBlock, newBlock) == newBlock) { - targets[i] = newBlock; - } - } - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/lir/LIRXirInstruction.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/lir/LIRXirInstruction.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,166 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.lir; - -import java.util.*; - -import com.sun.c1x.*; -import com.sun.c1x.gen.*; -import com.sun.cri.ci.*; -import com.sun.cri.ri.*; -import com.sun.cri.xir.*; - -public class LIRXirInstruction extends LIRInstruction { - - public final CiValue[] originalOperands; - public final int outputOperandIndex; - public final int[] operandIndices; - public final XirSnippet snippet; - public final RiMethod method; - public final int inputTempCount; - public final int tempCount; - public final int inputCount; - public final List pointerSlots; - public final LIRDebugInfo infoAfter; - - public LIRXirInstruction(XirSnippet snippet, - CiValue[] originalOperands, - CiValue outputOperand, - int inputTempCount, - int tempCount, - CiValue[] operands, - int[] operandIndices, - int outputOperandIndex, - LIRDebugInfo info, - LIRDebugInfo infoAfter, - RiMethod method, - List pointerSlots) { - super(LIROpcode.Xir, outputOperand, info, false, inputTempCount, tempCount, operands); - this.infoAfter = infoAfter; - this.pointerSlots = pointerSlots; - assert this.pointerSlots == null || this.pointerSlots.size() >= 0; - this.method = method; - this.snippet = snippet; - this.operandIndices = operandIndices; - this.outputOperandIndex = outputOperandIndex; - this.originalOperands = originalOperands; - this.inputTempCount = inputTempCount; - this.tempCount = tempCount; - this.inputCount = operands.length - inputTempCount - tempCount; - - C1XMetrics.LIRXIRInstructions++; - } - - public CiValue[] getOperands() { - for (int i = 0; i < operandIndices.length; i++) { - originalOperands[operandIndices[i]] = operand(i); - } - if (outputOperandIndex != -1) { - originalOperands[outputOperandIndex] = result(); - } - return originalOperands; - } - - /** - * Emits target assembly code for this instruction. - * - * @param masm the target assembler - */ - @Override - public void emitCode(LIRAssembler masm) { - masm.emitXir(this); - } - - /** - * Prints this instruction. - */ - @Override - public String operationString(OperandFormatter operandFmt) { - return toString(operandFmt); - } - - @Override - public String toString(OperandFormatter operandFmt) { - StringBuilder sb = new StringBuilder(); - sb.append("XIR: "); - - if (result().isLegal()) { - sb.append(operandFmt.format(result()) + " = "); - } - - sb.append(snippet.template); - sb.append("("); - for (int i = 0; i < snippet.arguments.length; i++) { - XirArgument a = snippet.arguments[i]; - if (i > 0) { - sb.append(", "); - } - if (a.constant != null) { - sb.append(operandFmt.format(a.constant)); - } else { - Object o = a.object; - if (o instanceof LIRItem) { - sb.append(operandFmt.format(((LIRItem) o).result())); - } else if (o instanceof CiValue) { - sb.append(operandFmt.format((CiValue) o)); - } else { - sb.append(o); - } - } - } - sb.append(')'); - - if (method != null) { - sb.append(" method="); - sb.append(method.toString()); - } - - - for (LIRInstruction.OperandMode mode : LIRInstruction.OPERAND_MODES) { - int n = operandCount(mode); - if (mode == OperandMode.Output && n <= 1) { - // Already printed single output (i.e. result()) - continue; - } - if (n != 0) { - sb.append(' ').append(mode.name().toLowerCase()).append("=("); - HashSet operands = new HashSet(); - for (int i = 0; i < n; i++) { - String operand = operandFmt.format(operandAt(mode, i)); - if (!operands.contains(operand)) { - if (!operands.isEmpty()) { - sb.append(", "); - } - operands.add(operand); - sb.append(operand); - } - } - sb.append(')'); - } - } - - appendDebugInfo(sb, operandFmt, info); - - return sb.toString(); - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/lir/package-info.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/lir/package-info.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/** - * @author Marcelo Cintra - * @author Thomas Wuerthinger - * - * Port of the backend (LIR) of the client compiler to Java. - */ -package com.sun.c1x.lir; diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/observer/CompilationEvent.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/observer/CompilationEvent.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,142 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.observer; - -import java.util.*; - -import com.oracle.graal.graph.*; -import com.sun.c1x.*; -import com.sun.c1x.alloc.*; -import com.sun.c1x.graph.*; -import com.sun.cri.ci.*; -import com.sun.cri.ri.*; - -/** - * An event that occurred during compilation. Instances of this class provide information about the event and the state - * of the compilation when the event was raised. {@link #getCompilation()} and {@link #getMethod()} are guaranteed to - * always return a non-{@code null} value. Other objects provided by getter methods may be {@code null}, - * depending on the available information when and where the event was triggered. - * - * @author Peter Hofer - */ -public class CompilationEvent { - - private final C1XCompilation compilation; - private final String label; - private Graph graph; - - private BlockMap blockMap; - private int codeSize = -1; - - private LinearScan allocator; - private CiTargetMethod targetMethod; - private boolean hirValid = false; - private boolean lirValid = false; - - private Interval[] intervals; - private int intervalsSize; - private Interval[] intervalsCopy = null; - - public CompilationEvent(C1XCompilation compilation) { - this(compilation, null); - } - - private CompilationEvent(C1XCompilation compilation, String label) { - assert compilation != null; - this.label = label; - this.compilation = compilation; - } - - public CompilationEvent(C1XCompilation compilation, String label, Graph graph, boolean hirValid, boolean lirValid) { - this(compilation, label); - this.graph = graph; - this.hirValid = hirValid; - this.lirValid = lirValid; - } - - public CompilationEvent(C1XCompilation compilation, String label, Graph graph, boolean hirValid, boolean lirValid, CiTargetMethod targetMethod) { - this(compilation, label, graph, hirValid, lirValid); - this.targetMethod = targetMethod; - } - - public CompilationEvent(C1XCompilation compilation, String label, BlockMap blockMap, int codeSize) { - this(compilation, label); - this.blockMap = blockMap; - this.codeSize = codeSize; - } - - public CompilationEvent(C1XCompilation compilation, String label, LinearScan allocator, Interval[] intervals, int intervalsSize) { - this(compilation, label); - this.allocator = allocator; - this.intervals = intervals; - this.intervalsSize = intervalsSize; - } - - public C1XCompilation getCompilation() { - return compilation; - } - - public String getLabel() { - return label; - } - - public RiMethod getMethod() { - return compilation.method; - } - - public BlockMap getBlockMap() { - return blockMap; - } - - public Graph getGraph() { - return graph; - } - - public LinearScan getAllocator() { - return allocator; - } - - public CiTargetMethod getTargetMethod() { - return targetMethod; - } - - public boolean isHIRValid() { - return hirValid; - } - - public boolean isLIRValid() { - return lirValid; - } - - public Interval[] getIntervals() { - if (intervalsCopy == null && intervals != null) { - // deferred copy of the valid range of the intervals array - intervalsCopy = Arrays.copyOf(intervals, intervalsSize); - } - return intervalsCopy; - } - - public int getCodeSize() { - return codeSize; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/observer/CompilationObserver.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/observer/CompilationObserver.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.observer; - -import com.sun.c1x.*; - -/** - * Interface for classes that observe events of an {@link ObservableCompiler}. - * - * @author Peter Hofer - */ -public interface CompilationObserver { - - /** - * Called when compilation of a method has started. This is always the first event raised for a particular - * {@link C1XCompilation}. - * - * @param event Information associated with the event and current state of the compilation. - */ - void compilationStarted(CompilationEvent event); - - /** - * Called when an event has occurred, for example that a particular phase in the compilation has been entered. - * - * @param event Information associated with the event and current state of the compilation. - */ - void compilationEvent(CompilationEvent event); - - /** - * Called when compilation of a method has completed (successfully or not). This is always the last event raised for - * a particular {@link C1XCompilation}. - * - * @param event Information associated with the event and current state of the compilation. - */ - void compilationFinished(CompilationEvent event); - -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/observer/ObservableCompiler.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/observer/ObservableCompiler.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,99 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.observer; - -import java.util.*; - -import com.sun.c1x.debug.*; - -/** - * Base class for compilers that notify subscribed {@link CompilationObserver CompilationObservers} of - * {@link CompilationEvent CompilationEvents} that occur during their compilations. - * - * @author Peter Hofer - */ -public class ObservableCompiler { - - private List observers; - - /** - * @return {@code true} if one or more observers are subscribed to receive notifications from this compiler, - * {@code false} otherwise. - */ - public boolean isObserved() { - return observers != null && !TTY.isSuppressed(); - } - - /** - * Add the specified observer to receive events from this compiler. - * - * @param observer The observer to add. - */ - public void addCompilationObserver(CompilationObserver observer) { - assert observer != null; - - if (observers == null) { - observers = new LinkedList(); - } - observers.add(observer); - } - - public void fireCompilationStarted(CompilationEvent event) { - if (isObserved()) { - for (CompilationObserver observer : observers) { - observer.compilationStarted(event); - } - } - } - - public void fireCompilationEvent(CompilationEvent event) { - if (isObserved()) { - for (CompilationObserver observer : observers) { - observer.compilationEvent(event); - } - } - } - - public void fireCompilationFinished(CompilationEvent event) { - if (isObserved()) { - for (CompilationObserver observer : observers) { - observer.compilationFinished(event); - } - } - } - - /** - * Remove the specified observer so that it no longer receives events from this compiler. - * - * @param observer The observer to remove. - */ - public void removeCompilationObserver(CompilationObserver observer) { - if (observers != null) { - observers.remove(observer); - if (observers.size() == 0) { - observers = null; - } - } - } - -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/observer/package-info.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/observer/package-info.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/** - * Classes and interfaces for observing compilations. - * - * @author Peter Hofer - */ -package com.sun.c1x.observer; diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/package-info.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/package-info.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,186 +0,0 @@ -/* - * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/** - * The top-level package in C1X containing options, metrics, timers and the main compiler class - * {@link com.sun.c1x.C1XCompiler}. - * - *

{@code C1XCompiler} Overview

- * - * C1X is intended to be used with multiple JVM's so makes no use of or reference to classes for a specific JVM, for - * example Maxine. - * - * The compiler is represented by the class {@code C1XCompiler}. {@code C1XCompiler} binds a specific target - * architecture and JVM interface to produce a usable compiler object. There are - * two variants of {@code compileMethod}, one of which is used when doing on stack replacement (OSR), discussed - * later. The main variant takes {@link com.sun.cri.ri.RiMethod} and {@link com.sun.cri.xir.RiXirGenerator} arguments. - * {@code RiMethod} is C1X's representation of a Java method and {@code RiXirGenerator} represents the interface through - * which the compiler requests the XIR for a given bytecode from the runtime system. - * - *

The C1X Compilation Process

- * - * {@link com.sun.c1x.C1XCompiler#compileMethod} creates a {@link C1XCompilation} instance and then returns the result of calling its - * {@link com.sun.c1x.C1XCompilation#compile} method. The {@code C1XCompilation} instance records whether {@code compileMethod} was invoked with - * the OSR variant, which is used later in the IR generation. - *

- * While there is only one {@code C1XCompiler} instance, there may be several compilations proceeding concurrently, each of - * which is represented by a unique {@code C1XCompilation} instance. The static method {@link com.sun.c1x.C1XCompilation#current}} returns the - * {@code C1XCompilation} instance associated with the current thread, and is managed using a {@link java.lang.ThreadLocal} variable. It - * is used when assigning the unique id that is used for tracing output to an HIR node. Each {@code C1XCompilation} instance - * has an associated {@link com.sun.cri.ci.CiStatistics} object that accumulates information about the compilation process, but is also - * used as a generator of, for example, basic block identifiers. - *

- * The compilation begins by calling {@link com.sun.c1x.C1XCompilation#emitHIR}, which creates the high-level intermediate representation (HIR) from the - * bytecodes of the method. The HIR is managed by the {@link com.sun.c1x.graph.IR} class, an instance of which is created by - * {@code emitHR}, which then calls the {{@link com.sun.c1x.graph.IR#build}} method and returns the result. The {@code C1XCompilation} and {@code IR} - * instances are are bi-directionally linked. - * - *

Supported backends

- * - *
    - *
  • AMD64/x64 with SSE2
  • - *
- * - *

Notes and Todos

This is a collection of notes about the C1X compiler, including future directions, - * refactorings, missing features, broken features, etc. - * - * - *

Anticipated Refactorings

- * - *
    - *
  • - * The HIR nodes {@link com.sun.c1x.ir.UnsafePrefetch}, {@link com.sun.c1x.ir.UnsafePutObject}, etc should be replaced by uses of the newer - * {@link com.sun.c1x.ir.LoadPointer} and {@link com.sun.c1x.ir.StorePointer} nodes. Currently, the unsafe nodes are only generated by - * the creation of an OSR entry. Benefit: reduce the number of different IR nodes.
  • - * - *
  • - * Add a field to optionally store an {@link com.sun.c1x.ir.Info} object for each HIR node, and remove the - * {@link com.sun.c1x.ir.Instruction#exceptionHandlers} field, the {@link com.sun.c1x.ir.Instruction#bci} field, and any fields to store the Java - * frame state in subclasses. Benefit: saves space if most HIR nodes do not have exception handlers, a bci or Java frame - * state. Removes virtual dispatch on accessing debug information for nodes. Allows any node, regardless of its type, to - * have info attached.
  • - * - *
  • - * Migrate all HIR nodes to use the immutable {@link com.sun.c1x.value.FrameStateInfo} for debugging information. The {@link com.sun.c1x.value.FrameState} - * class is mutable and used throughout graph building. Benefit: {@code FrameStateInfo} would save both total space in - * the IR graph prevent many bugs due to the mutability of {@code FrameState}.
  • - * - *
  • - * Move the {@code FrameState} class to an inner class, or combine entirely, with the {@link com.sun.c1x.graph.GraphBuilder} class. After - * the introduction of the {@code FrameStateInfo} into HIR nodes, the mutable value stack should only need to be - * accessed from the graph builder.
  • - * - *
- * - *

Missing or incomplete features

- * - * There are some features of C1 that were not ported forward or finished given the time constraints for the C1X port. A - * list appears below. - * - *
    - *
  • - * Deoptimization metadata. The locations of all local variables and stack values are not communicated back to the - * runtime system through the {@link com.sun.cri.ci.CiDebugInfo} class yet. Such values are known to the register allocator, and there - * vestigial logic to compute them still there in the - * {@link com.sun.c1x.alloc.LinearScan#computeDebugInfo} method. To complete this metadata, the - * {@link com.sun.c1x.alloc.LinearScan} class must implement the {@link ValueLocator} interface and pass it to the - * {@link com.sun.c1x.lir.LIRDebugInfo#createFrame} method after register allocation. The - * resulting debug info will be fed back to the runtime system by the existing logic that calls - * {@link com.sun.cri.ci.CiTargetMethod#recordCall(int, Object, CiDebugInfo, boolean)} and other methods. Obviously the runtime - * system will need to encode this metadata in a dense format, because it is huge.
  • - * - * - *
  • - * Tiered compilation support. C1 supported the ability to add instrumentation to branches, invocations, and checkcasts - * in order to feed profile information to the C2 compiler in a tiered compilation setup. It relied on adding some - * information to the HIR nodes that represent these operations ({@link Invoke}, {@link CheckCast}, etc). All of this - * logic was removed to simplify both the front end and back end in anticipation of designing a future instrumentation - * API. XIR should be general enough to allow instrumentation code to be added to invocation and checkcast sites, but - * currently has no support for adding code at branches. - * - *
  • - * - *
  • - * SPARC and other architecture support. There pretty well-delineated separation between the architecture-independent - * part of LIR backend and the architecture-dependent, but the only implementation that current exists is the X86 - * backend ({@link com.sun.c1x.target.amd64.AMD64Backend}, {@link com.sun.c1x.target.amd64.AMD64LIRGenerator}, {@link com.sun.c1x.target.amd64.AMD64LIRAssembler}, etc).
  • - * - *
  • - * XIR for safepoints. The C1X backend should use XIR to get the code for safepoints, but currently it still uses the - * handwritten logic (currently only compatible with Maxine).
  • - * - *
- * - *

Untested features

- * - *
    - * - *
  • - * Reference map for outgoing overflow arguments. If a C1X method calls another method that has overflow arguments, it - * is not clear if the outgoing overflow argument area, which may contain references, has the appropriate bits set in - * the reference map for the C1X method's frame. Such arguments may be live in the called method.
  • - * - *
  • - * Although it should work, inlining synchronized methods or methods with exception handlers hasn't been tested.
  • - *
  • - * On-stack replacement. C1X retains all of the special logic for performing an OSR compilation. This is basically a - * compilation with a second entrypoint for entry from the interpreter. However, the generation of a runtime-specific - * entry sequence was never tested.
  • - * - *
  • - * {@link com.sun.c1x.C1XIntrinsic Intrinsification} is the mechanism by which the compiler recognizes calls to special JDK or - * runtime methods and replaces them with custom code. It is enabled by the {@link com.sun.c1x.C1XOptions#OptIntrinsify} compiler - * option. The C1X backend has never been tested with intrinsified arithmetic or floating point operations. For best - * performance, it should generate specialized machine code for arithmetic and floating point, perhaps using global - * stubs for complex floating point operations.
    - * Note: Folding of special intrinsified methods is supported, tested, and working. The runtime system may - * register methods to be folded by using the - * {@link com.sun.c1x.C1XIntrinsic#registerFoldableMethod(RiMethod, java.lang.reflect.Method)} call. When the compiler encounters a - * call to such a registered method where the parameters are all constants, it invokes the supplied method with - * reflection. If the reflective call produces a value and does not throw an exception, C1X replaces the call to the - * method with the result.
  • - *
- * - *

Broken features

- * - *
    - *
  • - * {@link com.sun.c1x.opt.LoopPeeler Loop peeling} was written by Marcelo Cintra near the end of his internship. It was never completed - * and should be considered broken. It only remains as a sketch of how loop peeling would be implemented in C1X, or in - * case he would finish the implementation and test it.
  • - * - *
  • - * Calls to global stubs should allocate space on the caller's stack. On AMD64 currently, calls to global stubs poke the - * arguments onto the stack below the RSP (i.e. in the callee's stack). While normally this code sequence is - * uninterruptible and works fine in the VM, signal handlers triggered when debugging or inspecting this code sequence - * may destroy these values when the OS calls the signal handler. This requires knowing which global stubs are called - * before finalizing the frame size; currently only the calls to - * {@link com.sun.c1x.target.amd64.AMD64MacroAssembler#callRuntimeCalleeSaved} - * do not fit this pattern. This needs to be fixed so that all global stubs that are called by the assembled code are - * known before beginning assembling. The {@link com.sun.c1x.target.amd64.AMD64GlobalStubEmitter} controls how the global stubs accept their - * parameters. See {@link com.sun.c1x.target.amd64.AMD64GlobalStubEmitter#callerFrameContainsArguments} and its usages. - * - *
  • - *
- */ -package com.sun.c1x; diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/target/Backend.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/target/Backend.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.target; - -import java.lang.reflect.*; - -import com.oracle.max.asm.*; -import com.sun.c1x.*; -import com.sun.c1x.gen.*; -import com.sun.c1x.globalstub.*; -import com.sun.c1x.lir.*; -import com.sun.cri.ci.*; -import com.sun.cri.ri.*; -import com.sun.cri.xir.*; - -/** - * The {@code Backend} class represents a compiler backend for C1X. - * - * @author Ben L. Titzer - */ -public abstract class Backend { - public final C1XCompiler compiler; - - protected Backend(C1XCompiler compiler) { - this.compiler = compiler; - } - - public static Backend create(CiArchitecture arch, C1XCompiler compiler) { - String className = arch.getClass().getName().replace("com.oracle.max.asm", "com.sun.c1x") + "Backend"; - try { - Class c = Class.forName(className); - Constructor cons = c.getDeclaredConstructor(C1XCompiler.class); - return (Backend) cons.newInstance(compiler); - } catch (Exception e) { - throw new Error("Could not instantiate " + className, e); - } - } - - public abstract FrameMap newFrameMap(RiMethod method, int numberOfLocks); - public abstract LIRGenerator newLIRGenerator(C1XCompilation compilation); - public abstract LIRAssembler newLIRAssembler(C1XCompilation compilation); - public abstract AbstractAssembler newAssembler(RiRegisterConfig registerConfig); - public abstract GlobalStubEmitter newGlobalStubEmitter(); - public abstract CiXirAssembler newXirAssembler(); -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/target/amd64/AMD64Backend.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/target/amd64/AMD64Backend.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,85 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.target.amd64; - -import static com.sun.c1x.C1XCompilation.*; - -import com.oracle.max.asm.*; -import com.oracle.max.asm.target.amd64.*; -import com.sun.c1x.*; -import com.sun.c1x.gen.*; -import com.sun.c1x.globalstub.*; -import com.sun.c1x.lir.*; -import com.sun.c1x.target.*; -import com.sun.cri.ri.*; -import com.sun.cri.xir.*; - -/** - * The {@code X86Backend} class represents the backend for the AMD64 architecture. - * - * @author Ben L. Titzer - */ -public class AMD64Backend extends Backend { - - public AMD64Backend(C1XCompiler compiler) { - super(compiler); - } - /** - * Creates a new LIRGenerator for x86. - * @param compilation the compilation for which to create the LIR generator - * @return an appropriate LIR generator instance - */ - @Override - public LIRGenerator newLIRGenerator(C1XCompilation compilation) { - return new AMD64LIRGenerator(compilation); - } - - /** - * Creates a new LIRAssembler for x86. - * @param compilation the compilation for which to create the LIR assembler - * @return an appropriate LIR assembler instance - */ - @Override - public LIRAssembler newLIRAssembler(C1XCompilation compilation) { - return new AMD64LIRAssembler(compilation); - } - - @Override - public FrameMap newFrameMap(RiMethod method, int numberOfLocks) { - return new FrameMap(compilation(), method, numberOfLocks); - } - @Override - public AbstractAssembler newAssembler(RiRegisterConfig registerConfig) { - return new AMD64MacroAssembler(compiler.target, registerConfig); - } - - @Override - public CiXirAssembler newXirAssembler() { - return new AMD64XirAssembler(); - } - - @Override - public GlobalStubEmitter newGlobalStubEmitter() { - return new AMD64GlobalStubEmitter(compiler); - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/target/amd64/AMD64GlobalStubEmitter.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/target/amd64/AMD64GlobalStubEmitter.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,439 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.target.amd64; - -import static com.sun.cri.ci.CiCallingConvention.Type.*; - -import java.util.*; - -import com.oracle.max.asm.*; -import com.oracle.max.asm.target.amd64.*; -import com.oracle.max.asm.target.amd64.AMD64Assembler.*; -import com.sun.c1x.*; -import com.sun.c1x.asm.*; -import com.sun.c1x.globalstub.*; -import com.sun.cri.ci.*; -import com.sun.cri.ci.CiRegister.*; -import com.sun.cri.ri.*; -import com.sun.cri.xir.*; -import com.sun.cri.xir.CiXirAssembler.*; - -public class AMD64GlobalStubEmitter implements GlobalStubEmitter { - - public static final int ARGUMENT_SIZE = 8; - - private static final long FloatSignFlip = 0x8000000080000000L; - private static final long DoubleSignFlip = 0x8000000000000000L; - private static final CiRegister convertArgument = AMD64.xmm0; - private static final CiRegister convertResult = AMD64.rax; - private static final CiRegister negateArgument = AMD64.xmm0; - private static final CiRegister negateTemp = AMD64.xmm1; - - private TargetMethodAssembler tasm; - private AMD64MacroAssembler asm; - private final CiTarget target; - private int argsSize; - private int[] argOffsets; - private int resultOffset; - private int saveSize; - private int registerRestoreEpilogueOffset; - - private RiRuntime runtime; - private C1XCompiler compiler; - private CiRegister[] registersSaved; - - private boolean savedAllRegisters; - - public AMD64GlobalStubEmitter(C1XCompiler compiler) { - this.compiler = compiler; - this.target = compiler.target; - this.runtime = compiler.runtime; - } - - private void reset(CiKind resultKind, CiKind[] argTypes) { - asm = new AMD64MacroAssembler(compiler.target, compiler.globalStubRegisterConfig); - tasm = new TargetMethodAssembler(asm); - saveSize = 0; - argsSize = 0; - argOffsets = new int[argTypes.length]; - resultOffset = 0; - registerRestoreEpilogueOffset = -1; - registersSaved = null; - - for (int i = 0; i < argTypes.length; i++) { - argOffsets[i] = argsSize; - argsSize += ARGUMENT_SIZE; - } - - if (resultKind != CiKind.Void) { - if (argsSize == 0) { - argsSize = ARGUMENT_SIZE; - } - resultOffset = 0; - } - } - - public GlobalStub emit(CiRuntimeCall runtimeCall, RiRuntime runtime) { - reset(runtimeCall.resultKind, runtimeCall.arguments); - emitStandardForward(null, runtimeCall); - String name = "stub-" + runtimeCall; - CiTargetMethod targetMethod = tasm.finishTargetMethod(name, runtime, registerRestoreEpilogueOffset, true); - Object stubObject = runtime.registerGlobalStub(targetMethod, name); - return new GlobalStub(null, runtimeCall.resultKind, stubObject, argsSize, argOffsets, resultOffset); - } - - public GlobalStub emit(GlobalStub.Id stub, RiRuntime runtime) { - reset(stub.resultKind, stub.arguments); - - switch (stub) { - case f2i: - emitF2I(); - break; - case f2l: - emitF2L(); - break; - case d2i: - emitD2I(); - break; - case d2l: - emitD2L(); - break; - case fneg: - emitFNEG(); - break; - case dneg: - emitDNEG(); - break; - } - - String name = "stub-" + stub; - CiTargetMethod targetMethod = tasm.finishTargetMethod(name, runtime, registerRestoreEpilogueOffset, true); - Object stubObject = runtime.registerGlobalStub(targetMethod, name); - return new GlobalStub(stub, stub.resultKind, stubObject, argsSize, argOffsets, resultOffset); - } - - private CiValue allocateParameterOperand(XirParameter param, int parameterIndex) { - return new CiAddress(param.kind, AMD64.RSP, argumentIndexToStackOffset(parameterIndex)); - } - - private CiValue allocateResultOperand(XirOperand result) { - return new CiAddress(result.kind, AMD64.RSP, argumentIndexToStackOffset(0)); - } - - private CiValue allocateOperand(XirTemp temp, ArrayList allocatableRegisters) { - if (temp instanceof XirRegister) { - XirRegister fixed = (XirRegister) temp; - return fixed.register; - } - - return newRegister(temp.kind, allocatableRegisters); - } - - private CiValue newRegister(CiKind kind, ArrayList allocatableRegisters) { - assert kind != CiKind.Float && kind != CiKind.Double; - assert allocatableRegisters.size() > 0; - return allocatableRegisters.remove(allocatableRegisters.size() - 1).asValue(kind); - } - - public GlobalStub emit(XirTemplate template, RiRuntime runtime) { - C1XCompilation compilation = new C1XCompilation(compiler, null, -1, null); - try { - return emit(template, compilation); - } finally { - compilation.close(); - } - } - - public GlobalStub emit(XirTemplate template, C1XCompilation compilation) { - reset(template.resultOperand.kind, getArgumentKinds(template)); - compilation.initFrameMap(0); - compilation.frameMap().setFrameSize(frameSize()); - AMD64LIRAssembler assembler = new AMD64LIRAssembler(compilation); - asm = assembler.masm; - tasm = assembler.tasm; - - ArrayList allocatableRegisters = new ArrayList(Arrays.asList(compiler.globalStubRegisterConfig.getCategorizedAllocatableRegisters().get(RegisterFlag.CPU))); - for (XirTemp t : template.temps) { - if (t instanceof XirRegister) { - final XirRegister fixed = (XirRegister) t; - if (fixed.register.isRegister()) { - allocatableRegisters.remove(fixed.register.asRegister()); - } - } - } - - completeSavePrologue(); - - CiValue[] operands = new CiValue[template.variableCount]; - - XirOperand resultOperand = template.resultOperand; - - if (template.allocateResultOperand) { - CiValue outputOperand = CiValue.IllegalValue; - // This snippet has a result that must be separately allocated - // Otherwise it is assumed that the result is part of the inputs - if (resultOperand.kind != CiKind.Void && resultOperand.kind != CiKind.Illegal) { - outputOperand = allocateResultOperand(resultOperand); - assert operands[resultOperand.index] == null; - } - operands[resultOperand.index] = outputOperand; - } - - for (XirParameter param : template.parameters) { - assert !(param instanceof XirConstantOperand) : "constant parameters not supported for stubs"; - CiValue op = allocateParameterOperand(param, param.parameterIndex); - assert operands[param.index] == null; - - // Is the value destroyed? - if (template.isParameterDestroyed(param.parameterIndex)) { - CiValue newOp = newRegister(op.kind, allocatableRegisters); - assembler.moveOp(op, newOp, op.kind, null, false); - operands[param.index] = newOp; - } else { - operands[param.index] = op; - } - } - - for (XirConstant c : template.constants) { - assert operands[c.index] == null; - operands[c.index] = c.value; - } - - for (XirTemp t : template.temps) { - CiValue op = allocateOperand(t, allocatableRegisters); - assert operands[t.index] == null; - operands[t.index] = op; - } - - for (CiValue operand : operands) { - assert operand != null; - } - - Label[] labels = new Label[template.labels.length]; - for (int i = 0; i < labels.length; i++) { - labels[i] = new Label(); - } - - assert template.marks.length == 0 : "marks not supported in global stubs"; - assembler.emitXirInstructions(null, template.fastPath, labels, operands, null); - epilogue(); - CiTargetMethod targetMethod = tasm.finishTargetMethod(template.name, runtime, registerRestoreEpilogueOffset, true); - Object stubObject = runtime.registerGlobalStub(targetMethod, template.name); - return new GlobalStub(null, template.resultOperand.kind, stubObject, argsSize, argOffsets, resultOffset); - } - - private CiKind[] getArgumentKinds(XirTemplate template) { - CiXirAssembler.XirParameter[] params = template.parameters; - CiKind[] result = new CiKind[params.length]; - for (int i = 0; i < params.length; i++) { - result[i] = params[i].kind; - } - return result; - } - - private void negatePrologue() { - partialSavePrologue(negateArgument, negateTemp); - loadArgument(0, negateArgument); - } - - private void negateEpilogue() { - storeArgument(0, negateArgument); - epilogue(); - } - - private void emitDNEG() { - negatePrologue(); - asm.movsd(negateTemp, tasm.recordDataReferenceInCode(CiConstant.forLong(DoubleSignFlip))); - asm.xorpd(negateArgument, negateTemp); - negateEpilogue(); - } - - private void emitFNEG() { - negatePrologue(); - asm.movsd(negateTemp, tasm.recordDataReferenceInCode(CiConstant.forLong(FloatSignFlip))); - asm.xorps(negateArgument, negateTemp); - negateEpilogue(); - } - - private void convertPrologue() { - partialSavePrologue(convertArgument, convertResult); - loadArgument(0, convertArgument); - } - - private void convertEpilogue() { - storeArgument(0, convertResult); - epilogue(); - } - - private void emitD2L() { - emitCOMISSD(true, false); - } - - private void emitD2I() { - emitCOMISSD(true, true); - } - - private void emitF2L() { - emitCOMISSD(false, false); - } - - private void emitF2I() { - emitCOMISSD(false, true); - } - - private void emitCOMISSD(boolean isDouble, boolean isInt) { - convertPrologue(); - if (isDouble) { - asm.ucomisd(convertArgument, tasm.recordDataReferenceInCode(CiConstant.DOUBLE_0)); - } else { - asm.ucomiss(convertArgument, tasm.recordDataReferenceInCode(CiConstant.FLOAT_0)); - } - Label nan = new Label(); - Label ret = new Label(); - asm.jccb(ConditionFlag.parity, nan); - asm.jccb(ConditionFlag.below, ret); - - // input is > 0 -> return maxInt - // result register already contains 0x80000000, so subtracting 1 gives 0x7fffffff - asm.decrementl(convertResult, 1); - asm.jmpb(ret); - - // input is NaN -> return 0 - asm.bind(nan); - asm.xorptr(convertResult, convertResult); - - asm.bind(ret); - convertEpilogue(); - } - - private void emitStandardForward(GlobalStub.Id stub, CiRuntimeCall call) { - if (stub != null) { - assert stub.resultKind == call.resultKind; - assert stub.arguments.length == call.arguments.length; - for (int i = 0; i < stub.arguments.length; i++) { - assert stub.arguments[i] == call.arguments[i]; - } - } - - completeSavePrologue(); - forwardRuntimeCall(call); - epilogue(); - } - - private int argumentIndexToStackOffset(int index) { - // <-- lower addresses - // | stub frame | caller frame | - // | locals,savearea,retaddr | args ..... | - return frameSize() + (index + 1) * ARGUMENT_SIZE; - } - - private void loadArgument(int index, CiRegister register) { - asm.movq(register, new CiAddress(CiKind.Word, AMD64.RSP, argumentIndexToStackOffset(index))); - } - - private void storeArgument(int index, CiRegister register) { - asm.movq(new CiAddress(CiKind.Word, AMD64.RSP, argumentIndexToStackOffset(index)), register); - } - - private void partialSavePrologue(CiRegister... registersToSave) { - this.registersSaved = registersToSave; - this.saveSize = registersToSave.length * target.wordSize; - - // align to code size - int entryCodeOffset = runtime.codeOffset(); - if (entryCodeOffset != 0) { - asm.nop(entryCodeOffset); - } - asm.subq(AMD64.rsp, frameSize()); - - int index = 0; - for (CiRegister r : registersToSave) { - asm.movq(new CiAddress(CiKind.Word, AMD64.RSP, index * target.arch.wordSize), r); - index++; - } - - tasm.setFrameSize(frameSize()); - this.savedAllRegisters = false; - } - - private void completeSavePrologue() { - CiCalleeSaveArea csa = compiler.globalStubRegisterConfig.getCalleeSaveArea(); - this.saveSize = csa.size; - int entryCodeOffset = runtime.codeOffset(); - if (entryCodeOffset != 0) { - // align to code size - asm.nop(entryCodeOffset); - } - asm.subq(AMD64.rsp, frameSize()); - tasm.setFrameSize(frameSize()); - int frameToCSA = 0; - asm.save(csa, frameToCSA); - this.savedAllRegisters = true; - } - - private void epilogue() { - assert registerRestoreEpilogueOffset == -1; - registerRestoreEpilogueOffset = asm.codeBuffer.position(); - - if (savedAllRegisters) { - CiCalleeSaveArea csa = compiler.globalStubRegisterConfig.getCalleeSaveArea(); - int frameToCSA = 0; - asm.restore(csa, frameToCSA); - } else { - // saved only select registers - for (int index = 0; index < registersSaved.length; index++) { - CiRegister r = registersSaved[index]; - asm.movq(r, new CiAddress(CiKind.Word, AMD64.RSP, index * target.wordSize)); - } - registersSaved = null; - } - - // Restore rsp - asm.addq(AMD64.rsp, frameSize()); - asm.ret(0); - } - - private int frameSize() { - return target.alignFrameSize(saveSize); - } - - private void forwardRuntimeCall(CiRuntimeCall call) { - // Load arguments - CiCallingConvention cc = compiler.globalStubRegisterConfig.getCallingConvention(RuntimeCall, call.arguments, target); - for (int i = 0; i < cc.locations.length; ++i) { - CiValue location = cc.locations[i]; - loadArgument(i, location.asRegister()); - } - - // Call to the runtime - int before = asm.codeBuffer.position(); - asm.call(); - int after = asm.codeBuffer.position(); - tasm.recordDirectCall(before, after, call, null); - - if (call.resultKind != CiKind.Void) { - CiRegister returnRegister = compiler.globalStubRegisterConfig.getReturnRegister(call.resultKind); - this.storeArgument(0, returnRegister); - } - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/target/amd64/AMD64LIRAssembler.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/target/amd64/AMD64LIRAssembler.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2197 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.target.amd64; - -import static com.sun.cri.bytecode.Bytecodes.*; -import static com.sun.cri.ci.CiCallingConvention.Type.*; -import static com.sun.cri.ci.CiRegister.*; -import static com.sun.cri.ci.CiValue.*; -import static java.lang.Double.*; -import static java.lang.Float.*; - -import java.util.*; - -import com.oracle.max.asm.*; -import com.oracle.max.asm.target.amd64.*; -import com.oracle.max.asm.target.amd64.AMD64Assembler.*; -import com.sun.c1x.*; -import com.sun.c1x.debug.*; -import com.sun.c1x.gen.LIRGenerator.*; -import com.sun.c1x.globalstub.*; -import com.sun.c1x.ir.*; -import com.sun.c1x.lir.*; -import com.sun.c1x.lir.FrameMap.*; -import com.sun.c1x.util.*; -import com.sun.cri.ci.*; -import com.sun.cri.ci.CiAddress.*; -import com.sun.cri.ci.CiTargetMethod.*; -import com.sun.cri.xir.*; -import com.sun.cri.xir.CiXirAssembler.*; - -/** - * This class implements the x86-specific code generation for LIR. - */ -public final class AMD64LIRAssembler extends LIRAssembler { - - private static final Object[] NO_PARAMS = new Object[0]; - private static final long NULLWORD = 0; - private static final CiRegister SHIFTCount = AMD64.rcx; - - private static final long DoubleSignMask = 0x7FFFFFFFFFFFFFFFL; - - final CiTarget target; - final AMD64MacroAssembler masm; - final int wordSize; - final CiRegister rscratch1; - - public AMD64LIRAssembler(C1XCompilation compilation) { - super(compilation); - masm = (AMD64MacroAssembler) asm; - target = compilation.target; - wordSize = target.wordSize; - rscratch1 = compilation.registerConfig.getScratchRegister(); - } - - private CiAddress asAddress(CiValue value) { - if (value.isAddress()) { - return (CiAddress) value; - } - assert value.isStackSlot(); - return compilation.frameMap().toStackAddress((CiStackSlot) value); - } - - @Override - protected int initialFrameSizeInBytes() { - return frameMap.frameSize(); - } - - @Override - protected void emitReturn(CiValue result) { - // TODO: Consider adding safepoint polling at return! - masm.ret(0); - } - - @Override - protected void emitMonitorAddress(int monitor, CiValue dst) { - CiStackSlot slot = frameMap.toMonitorBaseStackAddress(monitor); - masm.leaq(dst.asRegister(), new CiAddress(slot.kind, AMD64.rsp.asValue(), slot.index() * target.arch.wordSize)); - } - - @Override - protected void emitBreakpoint() { - masm.int3(); - } - - @Override - protected void emitStackAllocate(StackBlock stackBlock, CiValue dst) { - masm.leaq(dst.asRegister(), compilation.frameMap().toStackAddress(stackBlock)); - } - - private void moveRegs(CiRegister fromReg, CiRegister toReg) { - if (fromReg != toReg) { - masm.mov(toReg, fromReg); - } - } - - private void swapReg(CiRegister a, CiRegister b) { - masm.xchgptr(a, b); - } - - private void const2reg(CiRegister dst, int constant) { - // Do not optimize with an XOR as this instruction may be between - // a CMP and a Jcc in which case the XOR will modify the condition - // flags and interfere with the Jcc. - masm.movl(dst, constant); - } - - private void const2reg(CiRegister dst, long constant) { - // Do not optimize with an XOR as this instruction may be between - // a CMP and a Jcc in which case the XOR will modify the condition - // flags and interfere with the Jcc. - masm.movq(dst, constant); - } - - private void const2reg(CiRegister dst, CiConstant constant) { - assert constant.kind == CiKind.Object; - // Do not optimize with an XOR as this instruction may be between - // a CMP and a Jcc in which case the XOR will modify the condition - // flags and interfere with the Jcc. - if (constant.isNull()) { - masm.movq(dst, 0x0L); - } else if (target.inlineObjects) { - tasm.recordDataReferenceInCode(constant); - masm.movq(dst, 0xDEADDEADDEADDEADL); - } else { - masm.movq(dst, tasm.recordDataReferenceInCode(constant)); - } - } - - @Override - public void emitTraps() { - for (int i = 0; i < C1XOptions.MethodEndBreakpointGuards; ++i) { - masm.int3(); - } - } - - private void const2reg(CiRegister dst, float constant) { - if (constant == 0.0f) { - masm.xorps(dst, dst); - } else { - masm.movflt(dst, tasm.recordDataReferenceInCode(CiConstant.forFloat(constant))); - } - } - - private void const2reg(CiRegister dst, double constant) { - if (constant == 0.0f) { - masm.xorpd(dst, dst); - } else { - masm.movdbl(dst, tasm.recordDataReferenceInCode(CiConstant.forDouble(constant))); - } - } - - @Override - protected void const2reg(CiValue src, CiValue dest, LIRDebugInfo info) { - assert src.isConstant(); - assert dest.isRegister(); - CiConstant c = (CiConstant) src; - - // Checkstyle: off - switch (c.kind) { - case Boolean : - case Byte : - case Char : - case Short : - case Jsr : - case Int : const2reg(dest.asRegister(), c.asInt()); break; - case Word : - case Long : const2reg(dest.asRegister(), c.asLong()); break; - case Object : const2reg(dest.asRegister(), c); break; - case Float : const2reg(asXmmFloatReg(dest), c.asFloat()); break; - case Double : const2reg(asXmmDoubleReg(dest), c.asDouble()); break; - default : throw Util.shouldNotReachHere(); - } - // Checkstyle: on - } - - @Override - protected void const2stack(CiValue src, CiValue dst) { - assert src.isConstant(); - assert dst.isStackSlot(); - CiStackSlot slot = (CiStackSlot) dst; - CiConstant c = (CiConstant) src; - - // Checkstyle: off - switch (c.kind) { - case Boolean : - case Byte : - case Char : - case Short : - case Jsr : - case Int : masm.movl(frameMap.toStackAddress(slot), c.asInt()); break; - case Float : masm.movl(frameMap.toStackAddress(slot), floatToRawIntBits(c.asFloat())); break; - case Object : movoop(frameMap.toStackAddress(slot), c); break; - case Long : masm.mov64(frameMap.toStackAddress(slot), c.asLong()); break; - case Double : masm.mov64(frameMap.toStackAddress(slot), doubleToRawLongBits(c.asDouble())); break; - default : throw Util.shouldNotReachHere("Unknown constant kind for const2stack: " + c.kind); - } - // Checkstyle: on - } - - @Override - protected void const2mem(CiValue src, CiValue dst, CiKind kind, LIRDebugInfo info) { - assert src.isConstant(); - assert dst.isAddress(); - CiConstant constant = (CiConstant) src; - CiAddress addr = asAddress(dst); - - int nullCheckHere = codePos(); - // Checkstyle: off - switch (kind) { - case Boolean : - case Byte : masm.movb(addr, constant.asInt() & 0xFF); break; - case Char : - case Short : masm.movw(addr, constant.asInt() & 0xFFFF); break; - case Jsr : - case Int : masm.movl(addr, constant.asInt()); break; - case Float : masm.movl(addr, floatToRawIntBits(constant.asFloat())); break; - case Object : movoop(addr, constant); break; - case Word: - case Long : masm.movq(rscratch1, constant.asLong()); - nullCheckHere = codePos(); - masm.movq(addr, rscratch1); break; - case Double : masm.movq(rscratch1, doubleToRawLongBits(constant.asDouble())); - nullCheckHere = codePos(); - masm.movq(addr, rscratch1); break; - default : throw Util.shouldNotReachHere(); - } - // Checkstyle: on - - if (info != null) { - tasm.recordImplicitException(nullCheckHere, info); - } - } - - @Override - protected void reg2reg(CiValue src, CiValue dest) { - assert src.isRegister(); - assert dest.isRegister(); - - if (dest.kind.isFloat()) { - masm.movflt(asXmmFloatReg(dest), asXmmFloatReg(src)); - } else if (dest.kind.isDouble()) { - masm.movdbl(asXmmDoubleReg(dest), asXmmDoubleReg(src)); - } else { - moveRegs(src.asRegister(), dest.asRegister()); - } - } - - @Override - protected void reg2stack(CiValue src, CiValue dst, CiKind kind) { - assert src.isRegister(); - assert dst.isStackSlot(); - CiAddress addr = frameMap.toStackAddress((CiStackSlot) dst); - - // Checkstyle: off - switch (src.kind) { - case Boolean : - case Byte : - case Char : - case Short : - case Jsr : - case Int : masm.movl(addr, src.asRegister()); break; - case Object : - case Word : - case Long : masm.movq(addr, src.asRegister()); break; - case Float : masm.movflt(addr, asXmmFloatReg(src)); break; - case Double : masm.movsd(addr, asXmmDoubleReg(src)); break; - default : throw Util.shouldNotReachHere(); - } - // Checkstyle: on - } - - @Override - protected void reg2mem(CiValue src, CiValue dest, CiKind kind, LIRDebugInfo info, boolean unaligned) { - CiAddress toAddr = (CiAddress) dest; - - if (info != null) { - tasm.recordImplicitException(codePos(), info); - } - - // Checkstyle: off - switch (kind) { - case Float : masm.movflt(toAddr, asXmmFloatReg(src)); break; - case Double : masm.movsd(toAddr, asXmmDoubleReg(src)); break; - case Jsr : - case Int : masm.movl(toAddr, src.asRegister()); break; - case Long : - case Word : - case Object : masm.movq(toAddr, src.asRegister()); break; - case Char : - case Short : masm.movw(toAddr, src.asRegister()); break; - case Byte : - case Boolean : masm.movb(toAddr, src.asRegister()); break; - default : throw Util.shouldNotReachHere(); - } - // Checkstyle: on - } - - private static CiRegister asXmmFloatReg(CiValue src) { - assert src.kind.isFloat() : "must be float, actual kind: " + src.kind; - CiRegister result = src.asRegister(); - assert result.isFpu() : "must be xmm, actual type: " + result; - return result; - } - - @Override - protected void stack2reg(CiValue src, CiValue dest, CiKind kind) { - assert src.isStackSlot(); - assert dest.isRegister(); - - CiAddress addr = frameMap.toStackAddress((CiStackSlot) src); - - // Checkstyle: off - switch (dest.kind) { - case Boolean : - case Byte : - case Char : - case Short : - case Jsr : - case Int : masm.movl(dest.asRegister(), addr); break; - case Object : - case Word : - case Long : masm.movq(dest.asRegister(), addr); break; - case Float : masm.movflt(asXmmFloatReg(dest), addr); break; - case Double : masm.movdbl(asXmmDoubleReg(dest), addr); break; - default : throw Util.shouldNotReachHere(); - } - // Checkstyle: on - } - - @Override - protected void mem2mem(CiValue src, CiValue dest, CiKind kind) { - if (dest.kind.isInt()) { - masm.pushl((CiAddress) src); - masm.popl((CiAddress) dest); - } else { - masm.pushptr((CiAddress) src); - masm.popptr((CiAddress) dest); - } - } - - @Override - protected void mem2stack(CiValue src, CiValue dest, CiKind kind) { - if (dest.kind.isInt()) { - masm.pushl((CiAddress) src); - masm.popl(frameMap.toStackAddress((CiStackSlot) dest)); - } else { - masm.pushptr((CiAddress) src); - masm.popptr(frameMap.toStackAddress((CiStackSlot) dest)); - } - } - - @Override - protected void stack2stack(CiValue src, CiValue dest, CiKind kind) { - if (src.kind.isInt()) { - masm.pushl(frameMap.toStackAddress((CiStackSlot) src)); - masm.popl(frameMap.toStackAddress((CiStackSlot) dest)); - } else { - masm.pushptr(frameMap.toStackAddress((CiStackSlot) src)); - masm.popptr(frameMap.toStackAddress((CiStackSlot) dest)); - } - } - - @Override - protected void mem2reg(CiValue src, CiValue dest, CiKind kind, LIRDebugInfo info, boolean unaligned) { - assert src.isAddress(); - assert dest.isRegister() : "dest=" + dest; - - CiAddress addr = (CiAddress) src; - if (info != null) { - tasm.recordImplicitException(codePos(), info); - } - - // Checkstyle: off - switch (kind) { - case Float : masm.movflt(asXmmFloatReg(dest), addr); break; - case Double : masm.movdbl(asXmmDoubleReg(dest), addr); break; - case Object : masm.movq(dest.asRegister(), addr); break; - case Int : masm.movslq(dest.asRegister(), addr); break; - case Word : - case Long : masm.movq(dest.asRegister(), addr); break; - case Boolean : - case Byte : masm.movsxb(dest.asRegister(), addr); break; - case Char : masm.movzxl(dest.asRegister(), addr); break; - case Short : masm.movswl(dest.asRegister(), addr); break; - default : throw Util.shouldNotReachHere(); - } - // Checkstyle: on - } - - @Override - protected void emitReadPrefetch(CiValue src) { - CiAddress addr = (CiAddress) src; - // Checkstyle: off - switch (C1XOptions.ReadPrefetchInstr) { - case 0 : masm.prefetchnta(addr); break; - case 1 : masm.prefetcht0(addr); break; - case 2 : masm.prefetcht2(addr); break; - default : throw Util.shouldNotReachHere(); - } - // Checkstyle: on - } - - @Override - protected void emitOp3(LIROp3 op) { - // Checkstyle: off - switch (op.code) { - case Idiv : - case Irem : arithmeticIdiv(op.code, op.opr1(), op.opr2(), op.result(), op.info); break; - case Ldiv : - case Lrem : arithmeticLdiv(op.code, op.opr1(), op.opr2(), op.result(), op.info); break; - case Wdiv : - case Wdivi : - case Wrem : - case Wremi : arithmeticWdiv(op.code, op.opr1(), op.opr2(), op.result(), op.info); break; - default : throw Util.shouldNotReachHere(); - } - // Checkstyle: on - } - - private boolean assertEmitBranch(LIRBranch op) { - assert op.block() == null || op.block().label() == op.label() : "wrong label"; - if (op.block() != null) { - branchTargetBlocks.add(op.block()); - } - if (op.unorderedBlock() != null) { - branchTargetBlocks.add(op.unorderedBlock()); - } - return true; - } - - private boolean assertEmitTableSwitch(LIRTableSwitch op) { - assert op.defaultTarget != null; - branchTargetBlocks.add(op.defaultTarget); - for (LIRBlock target : op.targets) { - assert target != null; - branchTargetBlocks.add(target); - } - return true; - } - - @Override - protected void emitTableSwitch(LIRTableSwitch op) { - - assert assertEmitTableSwitch(op); - - CiRegister value = op.value().asRegister(); - final Buffer buf = masm.codeBuffer; - - // Compare index against jump table bounds - int highKey = op.lowKey + op.targets.length - 1; - if (op.lowKey != 0) { - // subtract the low value from the switch value - masm.subl(value, op.lowKey); - masm.cmpl(value, highKey - op.lowKey); - } else { - masm.cmpl(value, highKey); - } - - // Jump to default target if index is not within the jump table - masm.jcc(ConditionFlag.above, op.defaultTarget.label()); - - // Set scratch to address of jump table - int leaPos = buf.position(); - buf.putMark(); - masm.leaq(rscratch1, new CiAddress(CiKind.Word, InstructionRelative.asValue(), 0)); - - // Load jump table entry into scratch and jump to it - masm.movslq(value, new CiAddress(CiKind.Int, rscratch1.asValue(), value.asValue(), Scale.Times4, 0)); - masm.addq(rscratch1, value); - masm.jmp(rscratch1); - - // Inserting padding so that jump table address is 4-byte aligned - if ((buf.position() & 0x3) != 0) { - masm.nop(4 - (buf.position() & 0x3)); - } - - // Patch LEA instruction above now that we know the position of the jump table - int jumpTablePos = buf.position(); - buf.setPosition(leaPos); - buf.putMark(); - masm.leaq(rscratch1, new CiAddress(CiKind.Word, InstructionRelative.asValue(), jumpTablePos - leaPos)); - buf.setPosition(jumpTablePos); - - // Emit jump table entries - for (LIRBlock target : op.targets) { - Label label = target.label(); - int offsetToJumpTableBase = buf.position() - jumpTablePos; - if (label.isBound()) { - int imm32 = label.position() - jumpTablePos; - buf.emitInt(imm32); - } else { - label.addPatchAt(buf.position()); - - buf.emitByte(0); // psuedo-opcode for jump table entry - buf.emitShort(offsetToJumpTableBase); - buf.emitByte(0); // padding to make jump table entry 4 bytes wide - } - } - - JumpTable jt = new JumpTable(jumpTablePos, op.lowKey, highKey, 4); - tasm.targetMethod.addAnnotation(jt); - } - - @Override - protected void emitBranch(LIRBranch op) { - - assert assertEmitBranch(op); - - if (op.cond() == Condition.TRUE) { - if (op.info != null) { - int codePos = codePos(); - if (codePos <= tasm.lastSafepointPos()) { - masm.nop(); - } - tasm.recordImplicitException(codePos(), op.info); - } - masm.jmp(op.label()); - } else { - ConditionFlag acond = ConditionFlag.zero; - if (op.code == LIROpcode.CondFloatBranch) { - assert op.unorderedBlock() != null : "must have unordered successor"; - masm.jcc(ConditionFlag.parity, op.unorderedBlock().label()); - // Checkstyle: off - switch (op.cond()) { - case EQ : acond = ConditionFlag.equal; break; - case NE : acond = ConditionFlag.notEqual; break; - case LT : acond = ConditionFlag.below; break; - case LE : acond = ConditionFlag.belowEqual; break; - case GE : acond = ConditionFlag.aboveEqual; break; - case GT : acond = ConditionFlag.above; break; - default : throw Util.shouldNotReachHere(); - } - } else { - switch (op.cond()) { - case EQ : acond = ConditionFlag.equal; break; - case NE : acond = ConditionFlag.notEqual; break; - case LT : acond = ConditionFlag.less; break; - case LE : acond = ConditionFlag.lessEqual; break; - case GE : acond = ConditionFlag.greaterEqual; break; - case GT : acond = ConditionFlag.greater; break; - case BE : acond = ConditionFlag.belowEqual; break; - case AE : acond = ConditionFlag.aboveEqual; break; - default : throw Util.shouldNotReachHere(); - } - // Checkstyle: on - } - masm.jcc(acond, op.label()); - } - } - - @Override - protected void emitConvert(LIRConvert op) { - CiValue src = op.operand(); - CiValue dest = op.result(); - Label endLabel = new Label(); - CiRegister srcRegister = src.asRegister(); - switch (op.bytecode) { - case I2L: - masm.movslq(dest.asRegister(), srcRegister); - break; - - case L2I: - moveRegs(srcRegister, dest.asRegister()); - masm.andl(dest.asRegister(), 0xFFFFFFFF); - break; - - case I2B: - moveRegs(srcRegister, dest.asRegister()); - masm.signExtendByte(dest.asRegister()); - break; - - case I2C: - moveRegs(srcRegister, dest.asRegister()); - masm.andl(dest.asRegister(), 0xFFFF); - break; - - case I2S: - moveRegs(srcRegister, dest.asRegister()); - masm.signExtendShort(dest.asRegister()); - break; - - case F2D: - masm.cvtss2sd(asXmmDoubleReg(dest), asXmmFloatReg(src)); - break; - - case D2F: - masm.cvtsd2ss(asXmmFloatReg(dest), asXmmDoubleReg(src)); - break; - - case I2F: - masm.cvtsi2ssl(asXmmFloatReg(dest), srcRegister); - break; - case I2D: - masm.cvtsi2sdl(asXmmDoubleReg(dest), srcRegister); - break; - - case F2I: { - assert srcRegister.isFpu() && dest.isRegister() : "must both be XMM register (no fpu stack)"; - masm.cvttss2sil(dest.asRegister(), srcRegister); - masm.cmp32(dest.asRegister(), Integer.MIN_VALUE); - masm.jcc(ConditionFlag.notEqual, endLabel); - callGlobalStub(op.globalStub, null, dest.asRegister(), src); - // cannot cause an exception - masm.bind(endLabel); - break; - } - case D2I: { - assert srcRegister.isFpu() && dest.isRegister() : "must both be XMM register (no fpu stack)"; - masm.cvttsd2sil(dest.asRegister(), asXmmDoubleReg(src)); - masm.cmp32(dest.asRegister(), Integer.MIN_VALUE); - masm.jcc(ConditionFlag.notEqual, endLabel); - callGlobalStub(op.globalStub, null, dest.asRegister(), src); - // cannot cause an exception - masm.bind(endLabel); - break; - } - case L2F: - masm.cvtsi2ssq(asXmmFloatReg(dest), srcRegister); - break; - - case L2D: - masm.cvtsi2sdq(asXmmDoubleReg(dest), srcRegister); - break; - - case F2L: { - assert srcRegister.isFpu() && dest.kind.isLong() : "must both be XMM register (no fpu stack)"; - masm.cvttss2siq(dest.asRegister(), asXmmFloatReg(src)); - masm.movq(rscratch1, java.lang.Long.MIN_VALUE); - masm.cmpq(dest.asRegister(), rscratch1); - masm.jcc(ConditionFlag.notEqual, endLabel); - callGlobalStub(op.globalStub, null, dest.asRegister(), src); - masm.bind(endLabel); - break; - } - - case D2L: { - assert srcRegister.isFpu() && dest.kind.isLong() : "must both be XMM register (no fpu stack)"; - masm.cvttsd2siq(dest.asRegister(), asXmmDoubleReg(src)); - masm.movq(rscratch1, java.lang.Long.MIN_VALUE); - masm.cmpq(dest.asRegister(), rscratch1); - masm.jcc(ConditionFlag.notEqual, endLabel); - callGlobalStub(op.globalStub, null, dest.asRegister(), src); - masm.bind(endLabel); - break; - } - - case MOV_I2F: - masm.movdl(asXmmFloatReg(dest), srcRegister); - break; - - case MOV_L2D: - masm.movdq(asXmmDoubleReg(dest), srcRegister); - break; - - case MOV_F2I: - masm.movdl(dest.asRegister(), asXmmFloatReg(src)); - break; - - case MOV_D2L: - masm.movdq(dest.asRegister(), asXmmDoubleReg(src)); - break; - - default: - throw Util.shouldNotReachHere(); - } - } - - @Override - protected void emitCompareAndSwap(LIRCompareAndSwap op) { - CiAddress address = new CiAddress(CiKind.Object, op.address(), 0); - CiRegister newval = op.newValue().asRegister(); - CiRegister cmpval = op.expectedValue().asRegister(); - assert cmpval == AMD64.rax : "wrong register"; - assert newval != null : "new val must be register"; - assert cmpval != newval : "cmp and new values must be in different registers"; - assert cmpval != address.base() : "cmp and addr must be in different registers"; - assert newval != address.base() : "new value and addr must be in different registers"; - assert cmpval != address.index() : "cmp and addr must be in different registers"; - assert newval != address.index() : "new value and addr must be in different registers"; - if (compilation.target.isMP) { - masm.lock(); - } - if (op.code == LIROpcode.CasInt) { - masm.cmpxchgl(newval, address); - } else { - assert op.code == LIROpcode.CasObj || op.code == LIROpcode.CasLong || op.code == LIROpcode.CasWord; - masm.cmpxchgq(newval, address); - } - } - - @Override - protected void emitConditionalMove(Condition condition, CiValue opr1, CiValue opr2, CiValue result) { - ConditionFlag acond; - ConditionFlag ncond; - switch (condition) { - case EQ: - acond = ConditionFlag.equal; - ncond = ConditionFlag.notEqual; - break; - case NE: - acond = ConditionFlag.notEqual; - ncond = ConditionFlag.equal; - break; - case LT: - acond = ConditionFlag.less; - ncond = ConditionFlag.greaterEqual; - break; - case LE: - acond = ConditionFlag.lessEqual; - ncond = ConditionFlag.greater; - break; - case GE: - acond = ConditionFlag.greaterEqual; - ncond = ConditionFlag.less; - break; - case GT: - acond = ConditionFlag.greater; - ncond = ConditionFlag.lessEqual; - break; - case BE: - acond = ConditionFlag.belowEqual; - ncond = ConditionFlag.above; - break; - case BT: - acond = ConditionFlag.below; - ncond = ConditionFlag.aboveEqual; - break; - case AE: - acond = ConditionFlag.aboveEqual; - ncond = ConditionFlag.below; - break; - case AT: - acond = ConditionFlag.above; - ncond = ConditionFlag.belowEqual; - break; - default: - throw Util.shouldNotReachHere(); - } - - CiValue def = opr1; // assume left operand as default - CiValue other = opr2; - - if (opr2.isRegister() && opr2.asRegister() == result.asRegister()) { - // if the right operand is already in the result register, then use it as the default - def = opr2; - other = opr1; - // and flip the condition - ConditionFlag tcond = acond; - acond = ncond; - ncond = tcond; - } - - if (def.isRegister()) { - reg2reg(def, result); - } else if (def.isStackSlot()) { - stack2reg(def, result, result.kind); - } else { - assert def.isConstant(); - const2reg(def, result, null); - } - - if (!other.isConstant()) { - // optimized version that does not require a branch - if (other.isRegister()) { - assert other.asRegister() != result.asRegister() : "other already overwritten by previous move"; - if (other.kind.isInt()) { - masm.cmovq(ncond, result.asRegister(), other.asRegister()); - } else { - masm.cmovq(ncond, result.asRegister(), other.asRegister()); - } - } else { - assert other.isStackSlot(); - CiStackSlot otherSlot = (CiStackSlot) other; - if (other.kind.isInt()) { - masm.cmovl(ncond, result.asRegister(), frameMap.toStackAddress(otherSlot)); - } else { - masm.cmovq(ncond, result.asRegister(), frameMap.toStackAddress(otherSlot)); - } - } - - } else { - // conditional move not available, use emit a branch and move - Label skip = new Label(); - masm.jcc(acond, skip); - if (other.isRegister()) { - reg2reg(other, result); - } else if (other.isStackSlot()) { - stack2reg(other, result, result.kind); - } else { - assert other.isConstant(); - const2reg(other, result, null); - } - masm.bind(skip); - } - } - - @Override - protected void emitArithOp(LIROpcode code, CiValue left, CiValue right, CiValue dest, LIRDebugInfo info) { - assert info == null : "should never be used : idiv/irem and ldiv/lrem not handled by this method"; - assert Util.archKindsEqual(left.kind, right.kind) || (left.kind == CiKind.Word && right.kind == CiKind.Int) : code.toString() + " left arch is " + left.kind + " and right arch is " + right.kind; - assert left.equals(dest) : "left and dest must be equal"; - CiKind kind = left.kind; - - // Checkstyle: off - if (left.isRegister()) { - CiRegister lreg = left.asRegister(); - - if (right.isRegister()) { - // register - register - CiRegister rreg = right.asRegister(); - if (kind.isInt()) { - switch (code) { - case Add : masm.addl(lreg, rreg); break; - case Sub : masm.subl(lreg, rreg); break; - case Mul : masm.imull(lreg, rreg); break; - default : throw Util.shouldNotReachHere(); - } - } else if (kind.isFloat()) { - assert rreg.isFpu() : "must be xmm"; - switch (code) { - case Add : masm.addss(lreg, rreg); break; - case Sub : masm.subss(lreg, rreg); break; - case Mul : masm.mulss(lreg, rreg); break; - case Div : masm.divss(lreg, rreg); break; - default : throw Util.shouldNotReachHere(); - } - } else if (kind.isDouble()) { - assert rreg.isFpu(); - switch (code) { - case Add : masm.addsd(lreg, rreg); break; - case Sub : masm.subsd(lreg, rreg); break; - case Mul : masm.mulsd(lreg, rreg); break; - case Div : masm.divsd(lreg, rreg); break; - default : throw Util.shouldNotReachHere(); - } - } else { - assert target.sizeInBytes(kind) == 8; - switch (code) { - case Add : masm.addq(lreg, rreg); break; - case Sub : masm.subq(lreg, rreg); break; - case Mul : masm.imulq(lreg, rreg); break; - default : throw Util.shouldNotReachHere(); - } - } - } else { - if (kind.isInt()) { - if (right.isStackSlot()) { - // register - stack - CiAddress raddr = frameMap.toStackAddress(((CiStackSlot) right)); - switch (code) { - case Add : masm.addl(lreg, raddr); break; - case Sub : masm.subl(lreg, raddr); break; - default : throw Util.shouldNotReachHere(); - } - } else if (right.isConstant()) { - // register - constant - assert kind.isInt(); - int delta = ((CiConstant) right).asInt(); - switch (code) { - case Add : masm.incrementl(lreg, delta); break; - case Sub : masm.decrementl(lreg, delta); break; - default : throw Util.shouldNotReachHere(); - } - } - } else if (kind.isFloat()) { - // register - stack/constant - CiAddress raddr; - if (right.isStackSlot()) { - raddr = frameMap.toStackAddress(((CiStackSlot) right)); - } else { - assert right.isConstant(); - raddr = tasm.recordDataReferenceInCode(CiConstant.forFloat(((CiConstant) right).asFloat())); - } - switch (code) { - case Add : masm.addss(lreg, raddr); break; - case Sub : masm.subss(lreg, raddr); break; - case Mul : masm.mulss(lreg, raddr); break; - case Div : masm.divss(lreg, raddr); break; - default : throw Util.shouldNotReachHere(); - } - } else if (kind.isDouble()) { - // register - stack/constant - CiAddress raddr; - if (right.isStackSlot()) { - raddr = frameMap.toStackAddress(((CiStackSlot) right)); - } else { - assert right.isConstant(); - raddr = tasm.recordDataReferenceInCode(CiConstant.forDouble(((CiConstant) right).asDouble())); - } - switch (code) { - case Add : masm.addsd(lreg, raddr); break; - case Sub : masm.subsd(lreg, raddr); break; - case Mul : masm.mulsd(lreg, raddr); break; - case Div : masm.divsd(lreg, raddr); break; - default : throw Util.shouldNotReachHere(); - } - } else { - assert target.sizeInBytes(kind) == 8; - if (right.isStackSlot()) { - // register - stack - CiAddress raddr = frameMap.toStackAddress(((CiStackSlot) right)); - switch (code) { - case Add : masm.addq(lreg, raddr); break; - case Sub : masm.subq(lreg, raddr); break; - default : throw Util.shouldNotReachHere(); - } - } else { - // register - constant - assert right.isConstant(); - long c = ((CiConstant) right).asLong(); - if (NumUtil.isInt(c)) { - switch (code) { - case Add : masm.addq(lreg, (int) c); break; - case Sub : masm.subq(lreg, (int) c); break; - default : throw Util.shouldNotReachHere(); - } - } else { - masm.movq(rscratch1, c); - switch (code) { - case Add : masm.addq(lreg, rscratch1); break; - case Sub : masm.subq(lreg, rscratch1); break; - default : throw Util.shouldNotReachHere(); - } - } - } - } - } - } else { - assert kind.isInt(); - CiAddress laddr = asAddress(left); - - if (right.isRegister()) { - CiRegister rreg = right.asRegister(); - switch (code) { - case Add : masm.addl(laddr, rreg); break; - case Sub : masm.subl(laddr, rreg); break; - default : throw Util.shouldNotReachHere(); - } - } else { - assert right.isConstant(); - int c = ((CiConstant) right).asInt(); - switch (code) { - case Add : masm.incrementl(laddr, c); break; - case Sub : masm.decrementl(laddr, c); break; - default : throw Util.shouldNotReachHere(); - } - } - } - // Checkstyle: on - } - - @Override - protected void emitIntrinsicOp(LIROpcode code, CiValue value, CiValue unused, CiValue dest, LIROp2 op) { - assert value.kind.isDouble(); - switch (code) { - case Abs: - if (asXmmDoubleReg(dest) != asXmmDoubleReg(value)) { - masm.movdbl(asXmmDoubleReg(dest), asXmmDoubleReg(value)); - } - masm.andpd(asXmmDoubleReg(dest), tasm.recordDataReferenceInCode(CiConstant.forLong(DoubleSignMask))); - break; - - case Sqrt: - masm.sqrtsd(asXmmDoubleReg(dest), asXmmDoubleReg(value)); - break; - - default: - throw Util.shouldNotReachHere(); - } - } - - @Override - protected void emitLogicOp(LIROpcode code, CiValue left, CiValue right, CiValue dst) { - assert left.isRegister(); - // Checkstyle: off - if (left.kind.isInt()) { - CiRegister reg = left.asRegister(); - if (right.isConstant()) { - int val = ((CiConstant) right).asInt(); - switch (code) { - case LogicAnd : masm.andl(reg, val); break; - case LogicOr : masm.orl(reg, val); break; - case LogicXor : masm.xorl(reg, val); break; - default : throw Util.shouldNotReachHere(); - } - } else if (right.isStackSlot()) { - // added support for stack operands - CiAddress raddr = frameMap.toStackAddress(((CiStackSlot) right)); - switch (code) { - case LogicAnd : masm.andl(reg, raddr); break; - case LogicOr : masm.orl(reg, raddr); break; - case LogicXor : masm.xorl(reg, raddr); break; - default : throw Util.shouldNotReachHere(); - } - } else { - CiRegister rright = right.asRegister(); - switch (code) { - case LogicAnd : masm.andq(reg, rright); break; - case LogicOr : masm.orq(reg, rright); break; - case LogicXor : masm.xorptr(reg, rright); break; - default : throw Util.shouldNotReachHere(); - } - } - moveRegs(reg, dst.asRegister()); - } else { - assert target.sizeInBytes(left.kind) == 8; - CiRegister lreg = left.asRegister(); - if (right.isConstant()) { - CiConstant rightConstant = (CiConstant) right; - masm.movq(rscratch1, rightConstant.asLong()); - switch (code) { - case LogicAnd : masm.andq(lreg, rscratch1); break; - case LogicOr : masm.orq(lreg, rscratch1); break; - case LogicXor : masm.xorq(lreg, rscratch1); break; - default : throw Util.shouldNotReachHere(); - } - } else { - CiRegister rreg = right.asRegister(); - switch (code) { - case LogicAnd : masm.andq(lreg, rreg); break; - case LogicOr : masm.orq(lreg, rreg); break; - case LogicXor : masm.xorptr(lreg, rreg); break; - default : throw Util.shouldNotReachHere(); - } - } - - CiRegister dreg = dst.asRegister(); - moveRegs(lreg, dreg); - } - // Checkstyle: on - } - - void arithmeticIdiv(LIROpcode code, CiValue left, CiValue right, CiValue result, LIRDebugInfo info) { - assert left.isRegister() : "left must be register"; - assert right.isRegister() || right.isConstant() : "right must be register or constant"; - assert result.isRegister() : "result must be register"; - - CiRegister lreg = left.asRegister(); - CiRegister dreg = result.asRegister(); - - if (right.isConstant()) { - int divisor = ((CiConstant) right).asInt(); - assert divisor > 0 && CiUtil.isPowerOf2(divisor) : "divisor must be power of two"; - if (code == LIROpcode.Idiv) { - assert lreg == AMD64.rax : "dividend must be rax"; - masm.cdql(); // sign extend into rdx:rax - if (divisor == 2) { - masm.subl(lreg, AMD64.rdx); - } else { - masm.andl(AMD64.rdx, divisor - 1); - masm.addl(lreg, AMD64.rdx); - } - masm.sarl(lreg, CiUtil.log2(divisor)); - moveRegs(lreg, dreg); - } else { - assert code == LIROpcode.Irem; - Label done = new Label(); - masm.mov(dreg, lreg); - masm.andl(dreg, 0x80000000 | (divisor - 1)); - masm.jcc(ConditionFlag.positive, done); - masm.decrementl(dreg, 1); - masm.orl(dreg, ~(divisor - 1)); - masm.incrementl(dreg, 1); - masm.bind(done); - } - } else { - CiRegister rreg = right.asRegister(); - assert lreg == AMD64.rax : "left register must be rax"; - assert rreg != AMD64.rdx : "right register must not be rdx"; - - moveRegs(lreg, AMD64.rax); - - Label continuation = new Label(); - - if (C1XOptions.GenSpecialDivChecks) { - // check for special case of Integer.MIN_VALUE / -1 - Label normalCase = new Label(); - masm.cmpl(AMD64.rax, Integer.MIN_VALUE); - masm.jcc(ConditionFlag.notEqual, normalCase); - if (code == LIROpcode.Irem) { - // prepare X86Register.rdx for possible special case where remainder = 0 - masm.xorl(AMD64.rdx, AMD64.rdx); - } - masm.cmpl(rreg, -1); - masm.jcc(ConditionFlag.equal, continuation); - - // handle normal case - masm.bind(normalCase); - } - masm.cdql(); - int offset = masm.codeBuffer.position(); - masm.idivl(rreg); - - // normal and special case exit - masm.bind(continuation); - - tasm.recordImplicitException(offset, info); - if (code == LIROpcode.Irem) { - moveRegs(AMD64.rdx, dreg); // result is in rdx - } else { - assert code == LIROpcode.Idiv; - moveRegs(AMD64.rax, dreg); - } - } - } - - void arithmeticLdiv(LIROpcode code, CiValue left, CiValue right, CiValue result, LIRDebugInfo info) { - assert left.isRegister() : "left must be register"; - assert right.isRegister() : "right must be register"; - assert result.isRegister() : "result must be register"; - assert result.kind.isLong(); - - CiRegister lreg = left.asRegister(); - CiRegister dreg = result.asRegister(); - CiRegister rreg = right.asRegister(); - assert lreg == AMD64.rax : "left register must be rax"; - assert rreg != AMD64.rdx : "right register must not be rdx"; - - moveRegs(lreg, AMD64.rax); - - Label continuation = new Label(); - - if (C1XOptions.GenSpecialDivChecks) { - // check for special case of Long.MIN_VALUE / -1 - Label normalCase = new Label(); - masm.movq(AMD64.rdx, java.lang.Long.MIN_VALUE); - masm.cmpq(AMD64.rax, AMD64.rdx); - masm.jcc(ConditionFlag.notEqual, normalCase); - if (code == LIROpcode.Lrem) { - // prepare X86Register.rdx for possible special case (where remainder = 0) - masm.xorq(AMD64.rdx, AMD64.rdx); - } - masm.cmpl(rreg, -1); - masm.jcc(ConditionFlag.equal, continuation); - - // handle normal case - masm.bind(normalCase); - } - masm.cdqq(); - int offset = masm.codeBuffer.position(); - masm.idivq(rreg); - - // normal and special case exit - masm.bind(continuation); - - tasm.recordImplicitException(offset, info); - if (code == LIROpcode.Lrem) { - moveRegs(AMD64.rdx, dreg); - } else { - assert code == LIROpcode.Ldiv; - moveRegs(AMD64.rax, dreg); - } - } - - void arithmeticWdiv(LIROpcode code, CiValue left, CiValue right, CiValue result, LIRDebugInfo info) { - assert left.isRegister() : "left must be register"; - assert right.isRegister() : "right must be register"; - assert result.isRegister() : "result must be register"; - - CiRegister lreg = left.asRegister(); - CiRegister dreg = result.asRegister(); - CiRegister rreg = right.asRegister(); - assert lreg == AMD64.rax : "left register must be rax"; - assert rreg != AMD64.rdx : "right register must not be rdx"; - - // Must zero the high 64-bit word (in RDX) of the dividend - masm.xorq(AMD64.rdx, AMD64.rdx); - - if (code == LIROpcode.Wdivi || code == LIROpcode.Wremi) { - // Zero the high 32 bits of the divisor - masm.movzxd(rreg, rreg); - } - - moveRegs(lreg, AMD64.rax); - - int offset = masm.codeBuffer.position(); - masm.divq(rreg); - - tasm.recordImplicitException(offset, info); - if (code == LIROpcode.Wrem || code == LIROpcode.Wremi) { - moveRegs(AMD64.rdx, dreg); - } else { - assert code == LIROpcode.Wdiv || code == LIROpcode.Wdivi; - moveRegs(AMD64.rax, dreg); - } - } - - @Override - protected void emitCompare(Condition condition, CiValue opr1, CiValue opr2, LIROp2 op) { - // Checkstyle: off - assert Util.archKindsEqual(opr1.kind.stackKind(), opr2.kind.stackKind()) || (opr1.kind == CiKind.Word && opr2.kind == CiKind.Int) : "nonmatching stack kinds (" + condition + "): " + opr1.kind.stackKind() + "==" + opr2.kind.stackKind(); - - if (opr1.isConstant()) { - // Use scratch register - CiValue newOpr1 = compilation.registerConfig.getScratchRegister().asValue(opr1.kind); - const2reg(opr1, newOpr1, null); - opr1 = newOpr1; - } - - if (opr1.isRegister()) { - CiRegister reg1 = opr1.asRegister(); - if (opr2.isRegister()) { - // register - register - switch (opr1.kind) { - case Boolean : - case Byte : - case Char : - case Short : - case Int : masm.cmpl(reg1, opr2.asRegister()); break; - case Long : - case Word : - case Object : masm.cmpq(reg1, opr2.asRegister()); break; - case Float : masm.ucomiss(reg1, asXmmFloatReg(opr2)); break; - case Double : masm.ucomisd(reg1, asXmmDoubleReg(opr2)); break; - default : throw Util.shouldNotReachHere(opr1.kind.toString()); - } - } else if (opr2.isStackSlot()) { - // register - stack - CiStackSlot opr2Slot = (CiStackSlot) opr2; - switch (opr1.kind) { - case Boolean : - case Byte : - case Char : - case Short : - case Int : masm.cmpl(reg1, frameMap.toStackAddress(opr2Slot)); break; - case Long : - case Word : - case Object : masm.cmpptr(reg1, frameMap.toStackAddress(opr2Slot)); break; - case Float : masm.ucomiss(reg1, frameMap.toStackAddress(opr2Slot)); break; - case Double : masm.ucomisd(reg1, frameMap.toStackAddress(opr2Slot)); break; - default : throw Util.shouldNotReachHere(); - } - } else if (opr2.isConstant()) { - // register - constant - CiConstant c = (CiConstant) opr2; - switch (opr1.kind) { - case Boolean : - case Byte : - case Char : - case Short : - case Int : masm.cmpl(reg1, c.asInt()); break; - case Float : masm.ucomiss(reg1, tasm.recordDataReferenceInCode(CiConstant.forFloat(((CiConstant) opr2).asFloat()))); break; - case Double : masm.ucomisd(reg1, tasm.recordDataReferenceInCode(CiConstant.forDouble(((CiConstant) opr2).asDouble()))); break; - case Long : - case Word : { - if (c.asLong() == 0) { - masm.cmpq(reg1, 0); - } else { - masm.movq(rscratch1, c.asLong()); - masm.cmpq(reg1, rscratch1); - - } - break; - } - case Object : { - movoop(rscratch1, c); - masm.cmpq(reg1, rscratch1); - break; - } - default : throw Util.shouldNotReachHere(); - } - } else { - throw Util.shouldNotReachHere(); - } - } else if (opr1.isStackSlot()) { - CiAddress left = asAddress(opr1); - if (opr2.isConstant()) { - CiConstant right = (CiConstant) opr2; - // stack - constant - switch (opr1.kind) { - case Boolean : - case Byte : - case Char : - case Short : - case Int : masm.cmpl(left, right.asInt()); break; - case Long : - case Word : assert NumUtil.isInt(right.asLong()); - masm.cmpq(left, right.asInt()); break; - case Object : assert right.isNull(); - masm.cmpq(left, 0); break; - default : throw Util.shouldNotReachHere(); - } - } else { - throw Util.shouldNotReachHere(); - } - - } else { - throw Util.shouldNotReachHere(opr1.toString() + " opr2 = " + opr2); - } - // Checkstyle: on - } - - @Override - protected void emitCompare2Int(LIROpcode code, CiValue left, CiValue right, CiValue dst, LIROp2 op) { - if (code == LIROpcode.Cmpfd2i || code == LIROpcode.Ucmpfd2i) { - if (left.kind.isFloat()) { - masm.cmpss2int(asXmmFloatReg(left), asXmmFloatReg(right), dst.asRegister(), code == LIROpcode.Ucmpfd2i); - } else if (left.kind.isDouble()) { - masm.cmpsd2int(asXmmDoubleReg(left), asXmmDoubleReg(right), dst.asRegister(), code == LIROpcode.Ucmpfd2i); - } else { - assert false : "no fpu stack"; - } - } else { - assert code == LIROpcode.Cmpl2i; - CiRegister dest = dst.asRegister(); - Label high = new Label(); - Label done = new Label(); - Label isEqual = new Label(); - masm.cmpptr(left.asRegister(), right.asRegister()); - masm.jcc(ConditionFlag.equal, isEqual); - masm.jcc(ConditionFlag.greater, high); - masm.xorptr(dest, dest); - masm.decrementl(dest, 1); - masm.jmp(done); - masm.bind(high); - masm.xorptr(dest, dest); - masm.incrementl(dest, 1); - masm.jmp(done); - masm.bind(isEqual); - masm.xorptr(dest, dest); - masm.bind(done); - } - } - - @Override - protected void emitCallAlignment(LIROpcode code) { - if (C1XOptions.AlignCallsForPatching) { - // make sure that the displacement word of the call ends up word aligned - int offset = masm.codeBuffer.position(); - offset += compilation.target.arch.machineCodeCallDisplacementOffset; - while (offset++ % wordSize != 0) { - masm.nop(); - } - } - } - - @Override - protected void emitIndirectCall(Object target, LIRDebugInfo info, CiValue callAddress) { - CiRegister reg = rscratch1; - if (callAddress.isRegister()) { - reg = callAddress.asRegister(); - } else { - moveOp(callAddress, reg.asValue(callAddress.kind), callAddress.kind, null, false); - } - indirectCall(reg, target, info); - } - - @Override - protected void emitDirectCall(Object target, LIRDebugInfo info) { - directCall(target, info); - } - - @Override - protected void emitNativeCall(String symbol, LIRDebugInfo info, CiValue callAddress) { - CiRegister reg = rscratch1; - if (callAddress.isRegister()) { - reg = callAddress.asRegister(); - } else { - moveOp(callAddress, reg.asValue(callAddress.kind), callAddress.kind, null, false); - } - indirectCall(reg, symbol, info); - } - - @Override - protected void emitTemplateCall(CiValue address) { - if (address == null) { - directCall(null, null); - return; - } - - CiRegister reg = rscratch1; - if (address.isRegister()) { - reg = address.asRegister(); - } else { - moveOp(address, reg.asValue(address.kind), address.kind, null, false); - } - indirectCall(reg, null, null); - } - - private void emitXIRShiftOp(LIROpcode code, CiValue left, CiValue count, CiValue dest) { - if (count.isConstant()) { - emitShiftOp(code, left, ((CiConstant) count).asInt(), dest); - } else { - emitShiftOp(code, left, count, dest, IllegalValue); - } - } - - @Override - protected void emitShiftOp(LIROpcode code, CiValue left, CiValue count, CiValue dest, CiValue tmp) { - // optimized version for linear scan: - // * count must be already in ECX (guaranteed by LinearScan) - // * left and dest must be equal - // * tmp must be unused - assert count.asRegister() == SHIFTCount : "count must be in ECX"; - assert left == dest : "left and dest must be equal"; - assert tmp.isIllegal() : "wasting a register if tmp is allocated"; - assert left.isRegister(); - - if (left.kind.isInt()) { - CiRegister value = left.asRegister(); - assert value != SHIFTCount : "left cannot be ECX"; - - // Checkstyle: off - switch (code) { - case Shl : masm.shll(value); break; - case Shr : masm.sarl(value); break; - case Ushr : masm.shrl(value); break; - default : throw Util.shouldNotReachHere(); - } - } else { - CiRegister lreg = left.asRegister(); - assert lreg != SHIFTCount : "left cannot be ECX"; - - switch (code) { - case Shl : masm.shlq(lreg); break; - case Shr : masm.sarq(lreg); break; - case Ushr : masm.shrq(lreg); break; - default : throw Util.shouldNotReachHere(); - } - // Checkstyle: on - } - } - - @Override - protected void emitShiftOp(LIROpcode code, CiValue left, int count, CiValue dest) { - assert dest.isRegister(); - if (dest.kind.isInt()) { - // first move left into dest so that left is not destroyed by the shift - CiRegister value = dest.asRegister(); - count = count & 0x1F; // Java spec - - moveRegs(left.asRegister(), value); - // Checkstyle: off - switch (code) { - case Shl : masm.shll(value, count); break; - case Shr : masm.sarl(value, count); break; - case Ushr : masm.shrl(value, count); break; - default : throw Util.shouldNotReachHere(); - } - } else { - - // first move left into dest so that left is not destroyed by the shift - CiRegister value = dest.asRegister(); - count = count & 0x1F; // Java spec - - moveRegs(left.asRegister(), value); - switch (code) { - case Shl : masm.shlq(value, count); break; - case Shr : masm.sarq(value, count); break; - case Ushr : masm.shrq(value, count); break; - default : throw Util.shouldNotReachHere(); - } - // Checkstyle: on - } - } - - @Override - protected void emitSignificantBitOp(boolean most, CiValue src, CiValue dst) { - assert dst.isRegister(); - CiRegister result = dst.asRegister(); - masm.xorq(result, result); - masm.notq(result); - if (src.isRegister()) { - CiRegister value = src.asRegister(); - assert value != result; - if (most) { - masm.bsrq(result, value); - } else { - masm.bsfq(result, value); - } - } else { - CiAddress laddr = asAddress(src); - if (most) { - masm.bsrq(result, laddr); - } else { - masm.bsfq(result, laddr); - } - } - } - - @Override - protected void emitAlignment() { - masm.align(wordSize); - } - - @Override - protected void emitNegate(LIRNegate op) { - CiValue left = op.operand(); - CiValue dest = op.result(); - assert left.isRegister(); - if (left.kind.isInt()) { - masm.negl(left.asRegister()); - moveRegs(left.asRegister(), dest.asRegister()); - - } else if (dest.kind.isFloat()) { - if (asXmmFloatReg(left) != asXmmFloatReg(dest)) { - masm.movflt(asXmmFloatReg(dest), asXmmFloatReg(left)); - } - callGlobalStub(op.globalStub, null, asXmmFloatReg(dest), dest); - - } else if (dest.kind.isDouble()) { - if (asXmmDoubleReg(left) != asXmmDoubleReg(dest)) { - masm.movdbl(asXmmDoubleReg(dest), asXmmDoubleReg(left)); - } - - callGlobalStub(op.globalStub, null, asXmmDoubleReg(dest), dest); - } else { - CiRegister lreg = left.asRegister(); - CiRegister dreg = dest.asRegister(); - masm.movq(dreg, lreg); - masm.negq(dreg); - } - } - - @Override - protected void emitLea(CiValue src, CiValue dest) { - CiRegister reg = dest.asRegister(); - masm.leaq(reg, asAddress(src)); - } - - @Override - protected void emitNullCheck(CiValue src, LIRDebugInfo info) { - assert src.isRegister(); - if (C1XOptions.NullCheckUniquePc) { - masm.nop(); - } - tasm.recordImplicitException(codePos(), info); - masm.nullCheck(src.asRegister()); - } - - @Override - protected void emitVolatileMove(CiValue src, CiValue dest, CiKind kind, LIRDebugInfo info) { - assert kind == CiKind.Long : "only for volatile long fields"; - - if (info != null) { - tasm.recordImplicitException(codePos(), info); - } - - if (src.kind.isDouble()) { - if (dest.isRegister()) { - masm.movdq(dest.asRegister(), asXmmDoubleReg(src)); - } else if (dest.isStackSlot()) { - masm.movsd(frameMap.toStackAddress((CiStackSlot) dest), asXmmDoubleReg(src)); - } else { - assert dest.isAddress(); - masm.movsd((CiAddress) dest, asXmmDoubleReg(src)); - } - } else { - assert dest.kind.isDouble(); - if (src.isStackSlot()) { - masm.movdbl(asXmmDoubleReg(dest), frameMap.toStackAddress((CiStackSlot) src)); - } else { - assert src.isAddress(); - masm.movdbl(asXmmDoubleReg(dest), (CiAddress) src); - } - } - } - - private static CiRegister asXmmDoubleReg(CiValue dest) { - assert dest.kind.isDouble() : "must be double XMM register"; - CiRegister result = dest.asRegister(); - assert result.isFpu() : "must be XMM register"; - return result; - } - - @Override - protected void emitMemoryBarriers(int barriers) { - masm.membar(barriers); - } - - @Override - protected void doPeephole(LIRList list) { - // Do nothing for now - } - - @Override - protected void emitXir(LIRXirInstruction instruction) { - XirSnippet snippet = instruction.snippet; - - Label[] labels = new Label[snippet.template.labels.length]; - for (int i = 0; i < labels.length; i++) { - labels[i] = new Label(); - } - emitXirInstructions(instruction, snippet.template.fastPath, labels, instruction.getOperands(), snippet.marks); - if (snippet.template.slowPath != null) { - addSlowPath(new SlowPath(instruction, labels, snippet.marks)); - } - } - - @Override - protected void emitSlowPath(SlowPath sp) { - int start = -1; - if (C1XOptions.TraceAssembler) { - TTY.println("Emitting slow path for XIR instruction " + sp.instruction.snippet.template.name); - start = masm.codeBuffer.position(); - } - emitXirInstructions(sp.instruction, sp.instruction.snippet.template.slowPath, sp.labels, sp.instruction.getOperands(), sp.marks); - masm.nop(); - if (C1XOptions.TraceAssembler) { - TTY.println("From " + start + " to " + masm.codeBuffer.position()); - } - } - - public void emitXirInstructions(LIRXirInstruction xir, XirInstruction[] instructions, Label[] labels, CiValue[] operands, Map marks) { - LIRDebugInfo info = xir == null ? null : xir.info; - LIRDebugInfo infoAfter = xir == null ? null : xir.infoAfter; - - for (XirInstruction inst : instructions) { - switch (inst.op) { - case Add: - emitArithOp(LIROpcode.Add, operands[inst.x().index], operands[inst.y().index], operands[inst.result.index], null); - break; - - case Sub: - emitArithOp(LIROpcode.Sub, operands[inst.x().index], operands[inst.y().index], operands[inst.result.index], null); - break; - - case Div: - if (inst.kind == CiKind.Int) { - arithmeticIdiv(LIROpcode.Idiv, operands[inst.x().index], operands[inst.y().index], operands[inst.result.index], null); - } else { - emitArithOp(LIROpcode.Div, operands[inst.x().index], operands[inst.y().index], operands[inst.result.index], null); - } - break; - - case Mul: - emitArithOp(LIROpcode.Mul, operands[inst.x().index], operands[inst.y().index], operands[inst.result.index], null); - break; - - case Mod: - if (inst.kind == CiKind.Int) { - arithmeticIdiv(LIROpcode.Irem, operands[inst.x().index], operands[inst.y().index], operands[inst.result.index], null); - } else { - emitArithOp(LIROpcode.Rem, operands[inst.x().index], operands[inst.y().index], operands[inst.result.index], null); - } - break; - - case Shl: - emitXIRShiftOp(LIROpcode.Shl, operands[inst.x().index], operands[inst.y().index], operands[inst.result.index]); - break; - - case Sar: - emitXIRShiftOp(LIROpcode.Shr, operands[inst.x().index], operands[inst.y().index], operands[inst.result.index]); - break; - - case Shr: - emitXIRShiftOp(LIROpcode.Ushr, operands[inst.x().index], operands[inst.y().index], operands[inst.result.index]); - break; - - case And: - emitLogicOp(LIROpcode.LogicAnd, operands[inst.x().index], operands[inst.y().index], operands[inst.result.index]); - break; - - case Or: - emitLogicOp(LIROpcode.LogicOr, operands[inst.x().index], operands[inst.y().index], operands[inst.result.index]); - break; - - case Xor: - emitLogicOp(LIROpcode.LogicXor, operands[inst.x().index], operands[inst.y().index], operands[inst.result.index]); - break; - - case Mov: { - CiValue result = operands[inst.result.index]; - CiValue source = operands[inst.x().index]; - moveOp(source, result, result.kind, null, false); - break; - } - - case PointerLoad: { - if ((Boolean) inst.extra && info != null) { - tasm.recordImplicitException(codePos(), info); - } - - CiValue result = operands[inst.result.index]; - CiValue pointer = operands[inst.x().index]; - CiRegisterValue register = assureInRegister(pointer); - moveOp(new CiAddress(inst.kind, register, 0), result, inst.kind, null, false); - break; - } - - case PointerStore: { - if ((Boolean) inst.extra && info != null) { - tasm.recordImplicitException(codePos(), info); - } - - CiValue value = operands[inst.y().index]; - CiValue pointer = operands[inst.x().index]; - assert pointer.isVariableOrRegister(); - moveOp(value, new CiAddress(inst.kind, pointer, 0), inst.kind, null, false); - break; - } - - case PointerLoadDisp: { - CiXirAssembler.AddressAccessInformation addressInformation = (CiXirAssembler.AddressAccessInformation) inst.extra; - boolean canTrap = addressInformation.canTrap; - - CiAddress.Scale scale = addressInformation.scale; - int displacement = addressInformation.disp; - - CiValue result = operands[inst.result.index]; - CiValue pointer = operands[inst.x().index]; - CiValue index = operands[inst.y().index]; - - pointer = assureInRegister(pointer); - assert pointer.isVariableOrRegister(); - - CiValue src = null; - if (index.isConstant()) { - assert index.kind == CiKind.Int; - CiConstant constantIndex = (CiConstant) index; - src = new CiAddress(inst.kind, pointer, constantIndex.asInt() * scale.value + displacement); - } else { - src = new CiAddress(inst.kind, pointer, index, scale, displacement); - } - - moveOp(src, result, inst.kind, canTrap ? info : null, false); - break; - } - - case LoadEffectiveAddress: { - CiXirAssembler.AddressAccessInformation addressInformation = (CiXirAssembler.AddressAccessInformation) inst.extra; - - CiAddress.Scale scale = addressInformation.scale; - int displacement = addressInformation.disp; - - CiValue result = operands[inst.result.index]; - CiValue pointer = operands[inst.x().index]; - CiValue index = operands[inst.y().index]; - - pointer = assureInRegister(pointer); - assert pointer.isVariableOrRegister(); - CiValue src = new CiAddress(CiKind.Illegal, pointer, index, scale, displacement); - emitLea(src, result); - break; - } - - case PointerStoreDisp: { - CiXirAssembler.AddressAccessInformation addressInformation = (CiXirAssembler.AddressAccessInformation) inst.extra; - boolean canTrap = addressInformation.canTrap; - - CiAddress.Scale scale = addressInformation.scale; - int displacement = addressInformation.disp; - - CiValue value = operands[inst.z().index]; - CiValue pointer = operands[inst.x().index]; - CiValue index = operands[inst.y().index]; - - pointer = assureInRegister(pointer); - assert pointer.isVariableOrRegister(); - - CiValue dst; - if (index.isConstant()) { - assert index.kind == CiKind.Int; - CiConstant constantIndex = (CiConstant) index; - dst = new CiAddress(inst.kind, pointer, IllegalValue, scale, constantIndex.asInt() * scale.value + displacement); - } else { - dst = new CiAddress(inst.kind, pointer, index, scale, displacement); - } - - moveOp(value, dst, inst.kind, canTrap ? info : null, false); - break; - } - - case RepeatMoveBytes: - assert operands[inst.x().index].asRegister().equals(AMD64.rsi) : "wrong input x: " + operands[inst.x().index]; - assert operands[inst.y().index].asRegister().equals(AMD64.rdi) : "wrong input y: " + operands[inst.y().index]; - assert operands[inst.z().index].asRegister().equals(AMD64.rcx) : "wrong input z: " + operands[inst.z().index]; - masm.repeatMoveBytes(); - break; - - case RepeatMoveWords: - assert operands[inst.x().index].asRegister().equals(AMD64.rsi) : "wrong input x: " + operands[inst.x().index]; - assert operands[inst.y().index].asRegister().equals(AMD64.rdi) : "wrong input y: " + operands[inst.y().index]; - assert operands[inst.z().index].asRegister().equals(AMD64.rcx) : "wrong input z: " + operands[inst.z().index]; - masm.repeatMoveWords(); - break; - - case PointerCAS: - - if ((Boolean) inst.extra && info != null) { - tasm.recordImplicitException(codePos(), info); - } - assert operands[inst.x().index].asRegister().equals(AMD64.rax) : "wrong input x: " + operands[inst.x().index]; - - CiValue exchangedVal = operands[inst.y().index]; - CiValue exchangedAddress = operands[inst.x().index]; - CiRegisterValue pointerRegister = assureInRegister(exchangedAddress); - CiAddress addr = new CiAddress(CiKind.Word, pointerRegister); - masm.cmpxchgq(exchangedVal.asRegister(), addr); - - break; - - case CallStub: { - XirTemplate stubId = (XirTemplate) inst.extra; - CiRegister result = CiRegister.None; - if (inst.result != null) { - result = operands[inst.result.index].asRegister(); - } - CiValue[] args = new CiValue[inst.arguments.length]; - for (int i = 0; i < args.length; i++) { - args[i] = operands[inst.arguments[i].index]; - } - callGlobalStub(stubId, info, result, args); - break; - } - case CallRuntime: { - CiKind[] signature = new CiKind[inst.arguments.length]; - for (int i = 0; i < signature.length; i++) { - signature[i] = inst.arguments[i].kind; - } - - CiCallingConvention cc = frameMap.getCallingConvention(signature, RuntimeCall); - for (int i = 0; i < inst.arguments.length; i++) { - CiValue argumentLocation = cc.locations[i]; - CiValue argumentSourceLocation = operands[inst.arguments[i].index]; - if (argumentLocation != argumentSourceLocation) { - moveOp(argumentSourceLocation, argumentLocation, argumentLocation.kind, null, false); - } - } - - RuntimeCallInformation runtimeCallInformation = (RuntimeCallInformation) inst.extra; - directCall(runtimeCallInformation.target, (runtimeCallInformation.useInfoAfter) ? infoAfter : info); - - if (inst.result != null && inst.result.kind != CiKind.Illegal && inst.result.kind != CiKind.Void) { - CiRegister returnRegister = compilation.registerConfig.getReturnRegister(inst.result.kind); - CiValue resultLocation = returnRegister.asValue(inst.result.kind.stackKind()); - moveOp(resultLocation, operands[inst.result.index], inst.result.kind.stackKind(), null, false); - } - break; - } - case Jmp: { - if (inst.extra instanceof XirLabel) { - Label label = labels[((XirLabel) inst.extra).index]; - masm.jmp(label); - } else { - directJmp(inst.extra); - } - break; - } - case DecAndJumpNotZero: { - Label label = labels[((XirLabel) inst.extra).index]; - CiValue value = operands[inst.x().index]; - if (value.kind == CiKind.Long) { - masm.decq(value.asRegister()); - } else { - assert value.kind == CiKind.Int; - masm.decl(value.asRegister()); - } - masm.jcc(ConditionFlag.notZero, label); - break; - } - case Jeq: { - Label label = labels[((XirLabel) inst.extra).index]; - emitXirCompare(inst, Condition.EQ, ConditionFlag.equal, operands, label); - break; - } - case Jneq: { - Label label = labels[((XirLabel) inst.extra).index]; - emitXirCompare(inst, Condition.NE, ConditionFlag.notEqual, operands, label); - break; - } - - case Jgt: { - Label label = labels[((XirLabel) inst.extra).index]; - emitXirCompare(inst, Condition.GT, ConditionFlag.greater, operands, label); - break; - } - - case Jgteq: { - Label label = labels[((XirLabel) inst.extra).index]; - emitXirCompare(inst, Condition.GE, ConditionFlag.greaterEqual, operands, label); - break; - } - - case Jugteq: { - Label label = labels[((XirLabel) inst.extra).index]; - emitXirCompare(inst, Condition.AE, ConditionFlag.aboveEqual, operands, label); - break; - } - - case Jlt: { - Label label = labels[((XirLabel) inst.extra).index]; - emitXirCompare(inst, Condition.LT, ConditionFlag.less, operands, label); - break; - } - - case Jlteq: { - Label label = labels[((XirLabel) inst.extra).index]; - emitXirCompare(inst, Condition.LE, ConditionFlag.lessEqual, operands, label); - break; - } - - case Jbset: { - Label label = labels[((XirLabel) inst.extra).index]; - CiValue pointer = operands[inst.x().index]; - CiValue offset = operands[inst.y().index]; - CiValue bit = operands[inst.z().index]; - assert offset.isConstant() && bit.isConstant(); - CiConstant constantOffset = (CiConstant) offset; - CiConstant constantBit = (CiConstant) bit; - CiAddress src = new CiAddress(inst.kind, pointer, constantOffset.asInt()); - masm.btli(src, constantBit.asInt()); - masm.jcc(ConditionFlag.aboveEqual, label); - break; - } - - case Bind: { - XirLabel l = (XirLabel) inst.extra; - Label label = labels[l.index]; - asm.bind(label); - break; - } - case Safepoint: { - assert info != null : "Must have debug info in order to create a safepoint."; - tasm.recordSafepoint(codePos(), info); - break; - } - case NullCheck: { - tasm.recordImplicitException(codePos(), info); - CiValue pointer = operands[inst.x().index]; - masm.nullCheck(pointer.asRegister()); - break; - } - case Align: { - masm.align((Integer) inst.extra); - break; - } - case StackOverflowCheck: { - int frameSize = initialFrameSizeInBytes(); - int lastFramePage = frameSize / target.pageSize; - // emit multiple stack bangs for methods with frames larger than a page - for (int i = 0; i <= lastFramePage; i++) { - int offset = (i + C1XOptions.StackShadowPages) * target.pageSize; - // Deduct 'frameSize' to handle frames larger than the shadow - bangStackWithOffset(offset - frameSize); - } - break; - } - case PushFrame: { - int frameSize = initialFrameSizeInBytes(); - masm.decrementq(AMD64.rsp, frameSize); // does not emit code for frameSize == 0 - if (C1XOptions.ZapStackOnMethodEntry) { - final int intSize = 4; - for (int i = 0; i < frameSize / intSize; ++i) { - masm.movl(new CiAddress(CiKind.Int, AMD64.rsp.asValue(), i * intSize), 0xC1C1C1C1); - } - } - CiCalleeSaveArea csa = compilation.registerConfig.getCalleeSaveArea(); - if (csa.size != 0) { - int frameToCSA = frameMap.offsetToCalleeSaveAreaStart(); - assert frameToCSA >= 0; - masm.save(csa, frameToCSA); - } - break; - } - case PopFrame: { - int frameSize = initialFrameSizeInBytes(); - - CiCalleeSaveArea csa = compilation.registerConfig.getCalleeSaveArea(); - if (csa.size != 0) { - registerRestoreEpilogueOffset = masm.codeBuffer.position(); - // saved all registers, restore all registers - int frameToCSA = frameMap.offsetToCalleeSaveAreaStart(); - masm.restore(csa, frameToCSA); - } - - masm.incrementq(AMD64.rsp, frameSize); - break; - } - case Push: { - CiRegisterValue value = assureInRegister(operands[inst.x().index]); - masm.push(value.asRegister()); - break; - } - case Pop: { - CiValue result = operands[inst.result.index]; - if (result.isRegister()) { - masm.pop(result.asRegister()); - } else { - masm.pop(rscratch1); - moveOp(rscratch1.asValue(), result, result.kind, null, true); - } - break; - } - case Mark: { - XirMark xmark = (XirMark) inst.extra; - Mark[] references = new Mark[xmark.references.length]; - for (int i = 0; i < references.length; i++) { - references[i] = marks.get(xmark.references[i]); - assert references[i] != null; - } - Mark mark = tasm.recordMark(xmark.id, references); - marks.put(xmark, mark); - break; - } - case Nop: { - for (int i = 0; i < (Integer) inst.extra; i++) { - masm.nop(); - } - break; - } - case RawBytes: { - for (byte b : (byte[]) inst.extra) { - masm.codeBuffer.emitByte(b & 0xff); - } - break; - } - case ShouldNotReachHere: { - if (inst.extra == null) { - stop("should not reach here"); - } else { - stop("should not reach here: " + inst.extra); - } - break; - } - default: - assert false : "Unknown XIR operation " + inst.op; - } - } - } - - /** - * @param offset the offset RSP at which to bang. Note that this offset is relative to RSP after RSP has been - * adjusted to allocated the frame for the method. It denotes an offset "down" the stack. - * For very large frames, this means that the offset may actually be negative (i.e. denoting - * a slot "up" the stack above RSP). - */ - private void bangStackWithOffset(int offset) { - masm.movq(new CiAddress(CiKind.Word, AMD64.RSP, -offset), AMD64.rax); - } - - private CiRegisterValue assureInRegister(CiValue pointer) { - if (pointer.isConstant()) { - CiRegisterValue register = rscratch1.asValue(pointer.kind); - moveOp(pointer, register, pointer.kind, null, false); - return register; - } - - assert pointer.isRegister() : "should be register, but is: " + pointer; - return (CiRegisterValue) pointer; - } - - private void emitXirCompare(XirInstruction inst, Condition condition, ConditionFlag cflag, CiValue[] ops, Label label) { - CiValue x = ops[inst.x().index]; - CiValue y = ops[inst.y().index]; - emitCompare(condition, x, y, null); - masm.jcc(cflag, label); - } - - @Override - public void emitDeoptizationStub(DeoptimizationStub stub) { - masm.bind(stub.label); - directCall(CiRuntimeCall.Deoptimize, stub.info); - shouldNotReachHere(); - } - - public GlobalStub lookupGlobalStub(XirTemplate template) { - return compilation.compiler.lookupGlobalStub(template); - } - - public void callGlobalStub(XirTemplate stub, LIRDebugInfo info, CiRegister result, CiValue... args) { - callGlobalStubHelper(lookupGlobalStub(stub), stub.resultOperand.kind, info, result, args); - } - - public void callGlobalStub(GlobalStub stub, LIRDebugInfo info, CiRegister result, CiValue... args) { - callGlobalStubHelper(stub, stub.resultKind, info, result, args); - } - - private void callGlobalStubHelper(GlobalStub stub, CiKind resultKind, LIRDebugInfo info, CiRegister result, CiValue... args) { - assert args.length == stub.argOffsets.length; - - for (int i = 0; i < args.length; i++) { - storeParameter(args[i], stub.argOffsets[i]); - } - - directCall(stub.stubObject, info); - - if (result != CiRegister.None) { - loadResult(result, stub.resultOffset, resultKind); - } - - // Clear out parameters - if (C1XOptions.GenAssertionCode) { - for (int i = 0; i < args.length; i++) { - masm.movptr(new CiAddress(CiKind.Word, AMD64.RSP, stub.argOffsets[i]), 0); - } - } - } - - private void loadResult(CiRegister r, int offset, CiKind kind) { - if (kind == CiKind.Int || kind == CiKind.Boolean) { - masm.movl(r, new CiAddress(CiKind.Int, AMD64.RSP, offset)); - } else if (kind == CiKind.Float) { - masm.movss(r, new CiAddress(CiKind.Float, AMD64.RSP, offset)); - } else if (kind == CiKind.Double) { - masm.movsd(r, new CiAddress(CiKind.Double, AMD64.RSP, offset)); - } else { - masm.movq(r, new CiAddress(CiKind.Word, AMD64.RSP, offset)); - } - } - - private void storeParameter(CiValue registerOrConstant, int offset) { - CiKind k = registerOrConstant.kind; - if (registerOrConstant.isConstant()) { - CiConstant c = (CiConstant) registerOrConstant; - if (c.kind == CiKind.Object) { - movoop(new CiAddress(CiKind.Word, AMD64.RSP, offset), c); - } else { - masm.movptr(new CiAddress(CiKind.Word, AMD64.RSP, offset), c.asInt()); - } - } else if (registerOrConstant.isRegister()) { - if (k.isFloat()) { - masm.movss(new CiAddress(CiKind.Float, AMD64.RSP, offset), registerOrConstant.asRegister()); - } else if (k.isDouble()) { - masm.movsd(new CiAddress(CiKind.Double, AMD64.RSP, offset), registerOrConstant.asRegister()); - } else { - masm.movq(new CiAddress(CiKind.Word, AMD64.RSP, offset), registerOrConstant.asRegister()); - } - } else { - throw new InternalError("should not reach here"); - } - } - - public void movoop(CiRegister dst, CiConstant obj) { - assert obj.kind == CiKind.Object; - if (obj.isNull()) { - masm.xorq(dst, dst); - } else { - if (target.inlineObjects) { - tasm.recordDataReferenceInCode(obj); - masm.movq(dst, 0xDEADDEADDEADDEADL); - } else { - masm.movq(dst, tasm.recordDataReferenceInCode(obj)); - } - } - } - - public void movoop(CiAddress dst, CiConstant obj) { - movoop(rscratch1, obj); - masm.movq(dst, rscratch1); - } - - public void directCall(Object target, LIRDebugInfo info) { - int before = masm.codeBuffer.position(); - masm.call(); - int after = masm.codeBuffer.position(); - tasm.recordDirectCall(before, after, target, info); - tasm.recordExceptionHandlers(after, info); - } - - public void directJmp(Object target) { - int before = masm.codeBuffer.position(); - masm.jmp(0, true); - int after = masm.codeBuffer.position(); - tasm.recordDirectCall(before, after, target, null); - } - - public void indirectCall(CiRegister dst, Object target, LIRDebugInfo info) { - int before = masm.codeBuffer.position(); - masm.call(dst); - int after = masm.codeBuffer.position(); - tasm.recordIndirectCall(before, after, target, info); - tasm.recordExceptionHandlers(after, info); - } - - protected void stop(String msg) { - if (C1XOptions.GenAssertionCode) { - // TODO: pass a pointer to the message - directCall(CiRuntimeCall.Debug, null); - masm.hlt(); - } - } - - public void shouldNotReachHere() { - stop("should not reach here"); - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/target/amd64/AMD64LIRGenerator.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/target/amd64/AMD64LIRGenerator.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,559 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.c1x.target.amd64; - -import com.oracle.max.asm.*; -import com.oracle.max.asm.target.amd64.*; -import com.sun.c1x.*; -import com.sun.c1x.gen.*; -import com.sun.c1x.globalstub.*; -import com.sun.c1x.ir.*; -import com.sun.c1x.lir.*; -import com.sun.c1x.util.*; -import com.sun.cri.bytecode.*; -import com.sun.cri.ci.*; -import com.sun.cri.ri.*; -import com.sun.cri.ri.RiType.*; -import com.sun.cri.xir.*; - -/** - * This class implements the X86-specific portion of the LIR generator. - */ -public class AMD64LIRGenerator extends LIRGenerator { - - private static final CiRegisterValue RAX_I = AMD64.rax.asValue(CiKind.Int); - private static final CiRegisterValue RAX_L = AMD64.rax.asValue(CiKind.Long); - private static final CiRegisterValue RAX_W = AMD64.rax.asValue(CiKind.Word); - private static final CiRegisterValue RDX_I = AMD64.rdx.asValue(CiKind.Int); - private static final CiRegisterValue RDX_L = AMD64.rdx.asValue(CiKind.Long); - - private static final CiRegisterValue LDIV_TMP = RDX_L; - - - /** - * The register in which MUL puts the result for 64-bit multiplication. - */ - private static final CiRegisterValue LMUL_OUT = RAX_L; - - private static final CiRegisterValue SHIFT_COUNT_IN = AMD64.rcx.asValue(CiKind.Int); - - protected static final CiValue ILLEGAL = CiValue.IllegalValue; - - public AMD64LIRGenerator(C1XCompilation compilation) { - super(compilation); - } - - @Override - protected boolean canStoreAsConstant(Value v, CiKind kind) { - if (kind == CiKind.Short || kind == CiKind.Char) { - // there is no immediate move of word values in asemblerI486.?pp - return false; - } - return v instanceof Constant; - } - - @Override - protected boolean canInlineAsConstant(Value v) { - if (v.kind == CiKind.Long) { - if (v.isConstant() && NumUtil.isInt(v.asConstant().asLong())) { - return true; - } - return false; - } - return v.kind != CiKind.Object || v.isNullConstant(); - } - - @Override - protected CiAddress genAddress(CiValue base, CiValue index, int shift, int disp, CiKind kind) { - assert base.isVariableOrRegister(); - if (index.isConstant()) { - return new CiAddress(kind, base, (((CiConstant) index).asInt() << shift) + disp); - } else { - assert index.isVariableOrRegister(); - return new CiAddress(kind, base, (index), CiAddress.Scale.fromShift(shift), disp); - } - } - - @Override - protected void genCmpMemInt(Condition condition, CiValue base, int disp, int c, LIRDebugInfo info) { - lir.cmpMemInt(condition, base, disp, c, info); - } - - @Override - protected void genCmpRegMem(Condition condition, CiValue reg, CiValue base, int disp, CiKind kind, LIRDebugInfo info) { - lir.cmpRegMem(condition, reg, new CiAddress(kind, base, disp), info); - } - - @Override - protected boolean strengthReduceMultiply(CiValue left, int c, CiValue result, CiValue tmp) { - if (tmp.isLegal()) { - if (CiUtil.isPowerOf2(c + 1)) { - lir.move(left, tmp); - lir.shiftLeft(left, CiUtil.log2(c + 1), left); - lir.sub(left, tmp, result); - return true; - } else if (CiUtil.isPowerOf2(c - 1)) { - lir.move(left, tmp); - lir.shiftLeft(left, CiUtil.log2(c - 1), left); - lir.add(left, tmp, result); - return true; - } - } - return false; - } - - @Override - public void visitNegate(Negate x) { - LIRItem value = new LIRItem(x.x(), this); - value.setDestroysRegister(); - value.loadItem(); - CiVariable reg = newVariable(x.kind); - GlobalStub globalStub = null; - if (x.kind == CiKind.Float) { - globalStub = stubFor(GlobalStub.Id.fneg); - } else if (x.kind == CiKind.Double) { - globalStub = stubFor(GlobalStub.Id.dneg); - } - lir.negate(value.result(), reg, globalStub); - setResult(x, reg); - } - - public boolean livesLonger(Value x, Value y) { - // TODO(tw): Estimate which value will live longer. - return false; - } - - public void visitArithmeticOpFloat(Arithmetic x) { - LIRItem left = new LIRItem(x.x(), this); - LIRItem right = new LIRItem(x.y(), this); - assert !left.isStack() || !right.isStack() : "can't both be memory operands"; - boolean mustLoadBoth = x.opcode == Bytecodes.FREM || x.opcode == Bytecodes.DREM; - - // Both are in register, swap operands such that the short-living one is on the left side. - if (x.isCommutative() && left.isRegisterOrVariable() && right.isRegisterOrVariable()) { - if (livesLonger(x.x(), x.y())) { - LIRItem tmp = left; - left = right; - right = tmp; - } - } - - if (left.isRegisterOrVariable() || x.x().isConstant() || mustLoadBoth) { - left.loadItem(); - } - - if (mustLoadBoth) { - // frem and drem destroy also right operand, so move it to a new register - right.setDestroysRegister(); - right.loadItem(); - } else if (right.isRegisterOrVariable()) { - right.loadItem(); - } - - CiVariable reg; - - if (x.opcode == Bytecodes.FREM) { - reg = callRuntimeWithResult(CiRuntimeCall.ArithmeticFrem, null, left.result(), right.result()); - } else if (x.opcode == Bytecodes.DREM) { - reg = callRuntimeWithResult(CiRuntimeCall.ArithmeticDrem, null, left.result(), right.result()); - } else { - reg = newVariable(x.kind); - arithmeticOpFpu(x.opcode, reg, left.result(), right.result(), ILLEGAL); - } - - setResult(x, reg); - } - - public void visitArithmeticOpLong(Arithmetic x) { - int opcode = x.opcode; - if (opcode == Bytecodes.LDIV || opcode == Bytecodes.LREM) { - // emit inline 64-bit code - LIRDebugInfo info = stateFor(x); - CiValue dividend = force(x.x(), RAX_L); // dividend must be in RAX - CiValue divisor = load(x.y()); // divisor can be in any (other) register - - CiValue result = createResultVariable(x); - CiValue resultReg; - if (opcode == Bytecodes.LREM) { - resultReg = RDX_L; // remainder result is produced in rdx - lir.lrem(dividend, divisor, resultReg, LDIV_TMP, info); - } else { - resultReg = RAX_L; // division result is produced in rax - lir.ldiv(dividend, divisor, resultReg, LDIV_TMP, info); - } - - lir.move(resultReg, result); - } else if (opcode == Bytecodes.LMUL) { - LIRItem right = new LIRItem(x.y(), this); - - // right register is destroyed by the long mul, so it must be - // copied to a new register. - right.setDestroysRegister(); - - CiValue left = load(x.x()); - right.loadItem(); - - arithmeticOpLong(opcode, LMUL_OUT, left, right.result(), null); - CiValue result = createResultVariable(x); - lir.move(LMUL_OUT, result); - } else { - LIRItem right = new LIRItem(x.y(), this); - - CiValue left = load(x.x()); - // don't load constants to save register - right.loadNonconstant(); - createResultVariable(x); - arithmeticOpLong(opcode, x.operand(), left, right.result(), null); - } - } - - public void visitArithmeticOpInt(Arithmetic x) { - int opcode = x.opcode; - if (opcode == Bytecodes.IDIV || opcode == Bytecodes.IREM) { - // emit code for integer division or modulus - - // Call 'stateFor' before 'force()' because 'stateFor()' may - // force the evaluation of other instructions that are needed for - // correct debug info. Otherwise the live range of the fixed - // register might be too long. - LIRDebugInfo info = stateFor(x); - - CiValue dividend = force(x.x(), RAX_I); // dividend must be in RAX - CiValue divisor = load(x.y()); // divisor can be in any (other) register - - // idiv and irem use rdx in their implementation so the - // register allocator must not assign it to an interval that overlaps - // this division instruction. - CiRegisterValue tmp = RDX_I; - - CiValue result = createResultVariable(x); - CiValue resultReg; - if (opcode == Bytecodes.IREM) { - resultReg = tmp; // remainder result is produced in rdx - lir.irem(dividend, divisor, resultReg, tmp, info); - } else { - resultReg = RAX_I; // division result is produced in rax - lir.idiv(dividend, divisor, resultReg, tmp, info); - } - - lir.move(resultReg, result); - } else { - // emit code for other integer operations - LIRItem left = new LIRItem(x.x(), this); - LIRItem right = new LIRItem(x.y(), this); - LIRItem leftArg = left; - LIRItem rightArg = right; - if (x.isCommutative() && left.isStack() && right.isRegisterOrVariable()) { - // swap them if left is real stack (or cached) and right is real register(not cached) - leftArg = right; - rightArg = left; - } - - leftArg.loadItem(); - - // do not need to load right, as we can handle stack and constants - if (opcode == Bytecodes.IMUL) { - // check if we can use shift instead - boolean useConstant = false; - boolean useTmp = false; - if (rightArg.result().isConstant()) { - int iconst = rightArg.instruction.asConstant().asInt(); - if (iconst > 0) { - if (CiUtil.isPowerOf2(iconst)) { - useConstant = true; - } else if (CiUtil.isPowerOf2(iconst - 1) || CiUtil.isPowerOf2(iconst + 1)) { - useConstant = true; - useTmp = true; - } - } - } - if (!useConstant) { - rightArg.loadItem(); - } - CiValue tmp = ILLEGAL; - if (useTmp) { - tmp = newVariable(CiKind.Int); - } - createResultVariable(x); - - arithmeticOpInt(opcode, x.operand(), leftArg.result(), rightArg.result(), tmp); - } else { - createResultVariable(x); - CiValue tmp = ILLEGAL; - arithmeticOpInt(opcode, x.operand(), leftArg.result(), rightArg.result(), tmp); - } - } - } - - public void visitArithmeticOpWord(Arithmetic x) { - int opcode = x.opcode; - if (opcode == Bytecodes.WDIV || opcode == Bytecodes.WREM || opcode == Bytecodes.WDIVI || opcode == Bytecodes.WREMI) { - // emit code for long division or modulus - // emit inline 64-bit code - LIRDebugInfo info = stateFor(x); - CiValue dividend = force(x.x(), RAX_L); // dividend must be in RAX - CiValue divisor = load(x.y()); // divisor can be in any (other) register - - CiValue result = createResultVariable(x); - CiValue resultReg; - if (opcode == Bytecodes.WREM) { - resultReg = RDX_L; // remainder result is produced in rdx - lir.wrem(dividend, divisor, resultReg, LDIV_TMP, info); - } else if (opcode == Bytecodes.WREMI) { - resultReg = RDX_L; // remainder result is produced in rdx - lir.wremi(dividend, divisor, resultReg, LDIV_TMP, info); - } else if (opcode == Bytecodes.WDIV) { - resultReg = RAX_L; // division result is produced in rax - lir.wdiv(dividend, divisor, resultReg, LDIV_TMP, info); - } else { - assert opcode == Bytecodes.WDIVI; - resultReg = RAX_L; // division result is produced in rax - lir.wdivi(dividend, divisor, resultReg, LDIV_TMP, info); - } - - lir.move(resultReg, result); - } else if (opcode == Bytecodes.LMUL) { - LIRItem right = new LIRItem(x.y(), this); - - // right register is destroyed by the long mul, so it must be - // copied to a new register. - right.setDestroysRegister(); - - CiValue left = load(x.x()); - right.loadItem(); - - CiValue reg = LMUL_OUT; - arithmeticOpLong(opcode, reg, left, right.result(), null); - CiValue result = createResultVariable(x); - lir.move(reg, result); - } else { - LIRItem right = new LIRItem(x.y(), this); - - CiValue left = load(x.x()); - // don't load constants to save register - right.loadNonconstant(); - createResultVariable(x); - arithmeticOpLong(opcode, x.operand(), left, right.result(), null); - } - } - - @Override - public void visitArithmetic(Arithmetic x) { - trySwap(x); - - if (x.kind.isWord() || x.opcode == Bytecodes.WREMI) { - visitArithmeticOpWord(x); - return; - } - - assert Util.archKindsEqual(x.x().kind, x.kind) && Util.archKindsEqual(x.y().kind, x.kind) : "wrong parameter types: " + Bytecodes.nameOf(x.opcode); - switch (x.kind) { - case Float: - case Double: - visitArithmeticOpFloat(x); - return; - case Long: - visitArithmeticOpLong(x); - return; - case Int: - visitArithmeticOpInt(x); - return; - } - throw Util.shouldNotReachHere(); - } - - @Override - public void visitShift(Shift x) { - // count must always be in rcx - CiValue count = makeOperand(x.y()); - boolean mustLoadCount = !count.isConstant() || x.kind == CiKind.Long; - if (mustLoadCount) { - // count for long must be in register - count = force(x.y(), SHIFT_COUNT_IN); - } - - CiValue value = load(x.x()); - CiValue reg = createResultVariable(x); - - shiftOp(x.opcode, reg, value, count, ILLEGAL); - } - - @Override - public void visitLogic(Logic x) { - trySwap(x); - - LIRItem right = new LIRItem(x.y(), this); - - CiValue left = load(x.x()); - right.loadNonconstant(); - CiValue reg = createResultVariable(x); - - logicOp(x.opcode, reg, left, right.result()); - } - - private void trySwap(Binary x) { - // (tw) TODO: Check what this is for? - } - - @Override - public void visitMaterialize(NormalizeCompare x) { - LIRItem left = new LIRItem(x.x(), this); - LIRItem right = new LIRItem(x.y(), this); - if (!x.kind.isVoid() && x.x().kind.isLong()) { - left.setDestroysRegister(); - } - left.loadItem(); - right.loadItem(); - - if (x.kind.isVoid()) { - lir.cmp(Condition.TRUE, left.result(), right.result()); - } else if (x.x().kind.isFloat() || x.x().kind.isDouble()) { - CiValue reg = createResultVariable(x); - int code = x.opcode; - lir.fcmp2int(left.result(), right.result(), reg, code == Bytecodes.FCMPL || code == Bytecodes.DCMPL); - } else if (x.x().kind.isLong() || x.x().kind.isWord()) { - CiValue reg = createResultVariable(x); - lir.lcmp2int(left.result(), right.result(), reg); - } else { - assert false; - } - } - - @Override - public void visitConvert(Convert x) { - CiValue input = load(x.value()); - CiVariable result = newVariable(x.kind); - // arguments of lirConvert - GlobalStub globalStub = null; - // Checkstyle: off - switch (x.opcode) { - case Bytecodes.F2I: globalStub = stubFor(GlobalStub.Id.f2i); break; - case Bytecodes.F2L: globalStub = stubFor(GlobalStub.Id.f2l); break; - case Bytecodes.D2I: globalStub = stubFor(GlobalStub.Id.d2i); break; - case Bytecodes.D2L: globalStub = stubFor(GlobalStub.Id.d2l); break; - } - // Checkstyle: on - if (globalStub != null) { - // Force result to be rax to match global stubs expectation. - CiValue stubResult = x.kind == CiKind.Int ? RAX_I : RAX_L; - lir.convert(x.opcode, input, stubResult, globalStub); - lir.move(stubResult, result); - } else { - lir.convert(x.opcode, input, result, globalStub); - } - setResult(x, result); - } - - @Override - public void visitMerge(Merge x) { - // nothing to do for now - } - - @Override - public void visitIf(If x) { - CiKind kind = x.compare().x().kind; - - Condition cond = x.compare().condition(); - - LIRItem xitem = new LIRItem(x.compare().x(), this); - LIRItem yitem = new LIRItem(x.compare().y(), this); - LIRItem xin = xitem; - LIRItem yin = yitem; - - if (kind.isLong()) { - // for longs, only conditions "eql", "neq", "lss", "geq" are valid; - // mirror for other conditions - if (cond == Condition.GT || cond == Condition.LE) { - cond = cond.mirror(); - xin = yitem; - yin = xitem; - } - xin.setDestroysRegister(); - } - xin.loadItem(); - if (kind.isLong() && yin.result().isConstant() && yin.instruction.asConstant().asLong() == 0 && (cond == Condition.EQ || cond == Condition.NE)) { - // dont load item - } else if (kind.isLong() || kind.isFloat() || kind.isDouble()) { - // longs cannot handle constants at right side - yin.loadItem(); - } - - setNoResult(x); - - CiValue left = xin.result(); - CiValue right = yin.result(); - lir.cmp(cond, left, right); - if (x.compare().x().kind.isFloat() || x.compare().x().kind.isDouble()) { - Instruction unorderedSucc = x.falseSuccessor(); - if (x.compare().unorderedIsTrue()) { - unorderedSucc = x.trueSuccessor(); - } - lir.branch(cond, right.kind, getLIRBlock(x.trueSuccessor()), getLIRBlock(unorderedSucc)); - } else { - lir.branch(cond, right.kind, getLIRBlock(x.trueSuccessor())); - } - assert x.defaultSuccessor() == x.falseSuccessor() : "wrong destination above"; - lir.jump(getLIRBlock(x.defaultSuccessor())); - } - - @Override - public void visitExceptionDispatch(ExceptionDispatch x) { - // TODO ls: this needs some more work... - - RiType riType = x.catchType(); - assert riType.isResolved(); - - XirArgument obj = toXirArgument(x.exception()); - XirArgument clazz = toXirArgument(riType.getEncoding(Representation.ObjectHub)); - XirSnippet snippet = xir.genInstanceOf(site(x), obj, clazz, riType); - CiValue result = emitXir(snippet, x, stateFor(x), null, true); - - lir.cmp(Condition.EQ, result, CiConstant.TRUE); - lir.branch(Condition.EQ, CiKind.Boolean, getLIRBlock(x.catchSuccessor())); - - lir.jump(getLIRBlock(x.otherSuccessor())); - } - - @Override - public void visitLoopBegin(LoopBegin x) { - visitMerge(x); - } - - @Override - public void visitLoopEnd(LoopEnd x) { - setNoResult(x); - - // emit phi-instruction moves after safepoint since this simplifies - // describing the state at the safepoint. - - moveToPhi(); - lir.jump(getLIRBlock(x.loopBegin())); - } - - @Override - public void visitValueAnchor(ValueAnchor valueAnchor) { - // nothing to do for ValueAnchors - } - -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/target/amd64/AMD64XirAssembler.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/target/amd64/AMD64XirAssembler.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,220 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.target.amd64; - -import static com.sun.cri.xir.XirTemplate.GlobalFlags.*; - -import java.util.*; - -import com.oracle.max.asm.target.amd64.*; -import com.sun.cri.ci.*; -import com.sun.cri.xir.*; - -/** - * AMD64 version of {@link CiXirAssembler}. - * - * @author Thomas Wuerthinger - * - */ -public class AMD64XirAssembler extends CiXirAssembler { - - @Override - protected XirTemplate buildTemplate(String name, boolean isStub) { - List fastPath = new ArrayList(instructions.size()); - List slowPath = new ArrayList(); - List calleeTemplates = new ArrayList(); - - int flags = 0; - - if (isStub) { - flags |= GLOBAL_STUB.mask; - } - - List currentList = fastPath; - - XirOperand fixedRDX = null; - XirOperand fixedRAX = null; - XirOperand fixedRCX = null; - XirOperand fixedRSI = null; - XirOperand fixedRDI = null; - HashSet boundLabels = new HashSet(); - - for (XirInstruction i : instructions) { - boolean appended = false; - switch (i.op) { - case Mov: - break; - - case Add: - case Sub: - case Div: - case Mul: - case Mod: - case Shl: - case Shr: - case And: - case Or: - case Xor: - // Convert to two operand form - XirOperand xOp = i.x(); - if (i.op == XirOp.Div || i.op == XirOp.Mod) { - if (fixedRDX == null) { - fixedRDX = createRegisterTemp("divModTemp", CiKind.Int, AMD64.rdx); - } - // Special treatment to make sure that the left input of % and / is in RAX - if (fixedRAX == null) { - fixedRAX = createRegisterTemp("divModLeftInput", CiKind.Int, AMD64.rax); - } - currentList.add(new XirInstruction(i.x().kind, XirOp.Mov, fixedRAX, i.x())); - xOp = fixedRAX; - } else { - if (i.result != i.x()) { - currentList.add(new XirInstruction(i.result.kind, XirOp.Mov, i.result, i.x())); - xOp = i.result; - } - } - - XirOperand yOp = i.y(); - if ((i.op == XirOp.Shl || i.op == XirOp.Shr) && (!(i.y() instanceof XirConstantOperand))) { - // Special treatment to make sure that the shift count is always in RCX - if (fixedRCX == null) { - fixedRCX = createRegisterTemp("fixedShiftCount", i.y().kind, AMD64.rcx); - } - currentList.add(new XirInstruction(i.result.kind, XirOp.Mov, fixedRCX, i.y())); - yOp = fixedRCX; - } else if (i.op == XirOp.Mul && (i.y() instanceof XirConstantOperand)) { - // Cannot multiply directly with a constant, so introduce a new temporary variable - XirOperand tempLocation = createTemp("mulTempLocation", i.y().kind); - currentList.add(new XirInstruction(i.result.kind, XirOp.Mov, tempLocation, i.y())); - yOp = tempLocation; - - } - - if (xOp != i.x() || yOp != i.y()) { - currentList.add(new XirInstruction(i.result.kind, i.op, i.result, xOp, yOp)); - appended = true; - } - break; - - case RepeatMoveWords: - case RepeatMoveBytes: - if (fixedRSI == null) { - fixedRSI = createRegisterTemp("fixedRSI", CiKind.Word, AMD64.rsi); - } - if (fixedRDI == null) { - fixedRDI = createRegisterTemp("fixedRDI", CiKind.Word, AMD64.rdi); - } - if (fixedRCX == null) { - fixedRCX = createRegisterTemp("fixedRCX", CiKind.Word, AMD64.rcx); - } - currentList.add(new XirInstruction(CiKind.Word, XirOp.Mov, fixedRSI, i.x())); - currentList.add(new XirInstruction(CiKind.Word, XirOp.Mov, fixedRDI, i.y())); - currentList.add(new XirInstruction(CiKind.Word, XirOp.Mov, fixedRCX, i.z())); - currentList.add(new XirInstruction(CiKind.Illegal, i.op, i.result, fixedRSI, fixedRDI, fixedRCX)); - appended = true; - break; - - case NullCheck: - case PointerLoad: - case LoadEffectiveAddress: - case PointerStore: - case PointerLoadDisp: - case PointerStoreDisp: - break; - case PointerCAS: - if (fixedRAX == null) { - fixedRAX = createRegisterTemp("fixedRAX", CiKind.Word, AMD64.rax); - } - // x = source of cmpxch - // y = new value - // z = old value (i.e., the one compared to). Must be in RAX (and so must the result). - currentList.add(new XirInstruction(CiKind.Word, XirOp.Mov, fixedRAX, i.z())); - currentList.add(new XirInstruction(i.kind, i.op, i.result, i.x(), i.y(), fixedRAX)); - appended = true; - break; - case CallStub: - flags |= HAS_STUB_CALL.mask; - calleeTemplates.add((XirTemplate) i.extra); - break; - case CallRuntime: - flags |= HAS_RUNTIME_CALL.mask; - break; - case Jmp: - // jmp can be either into the snippet or to a runtime target - flags |= i.extra instanceof XirLabel ? HAS_CONTROL_FLOW.mask : HAS_RUNTIME_CALL.mask; - break; - case Jeq: - case Jneq: - case Jgt: - case Jgteq: - case Jugteq: - case Jlt: - case Jlteq: - case DecAndJumpNotZero: - case Jbset: - flags |= HAS_CONTROL_FLOW.mask; - break; - case Bind: - XirLabel label = (XirLabel) i.extra; - currentList = label.inline ? fastPath : slowPath; - assert !boundLabels.contains(label) : "label may be bound only once"; - boundLabels.add(label); - break; - case Safepoint: - case Align: - case StackOverflowCheck: - case PushFrame: - case PopFrame: - case Push: - case Pop: - case Mark: - case Nop: - case RawBytes: - case ShouldNotReachHere: - break; - default: - assert false : "Unknown XIR operation " + i.op; - } - if (!appended) { - currentList.add(i); - } - } - for (XirLabel label : labels) { - assert boundLabels.contains(label) : "label " + label.name + " is not bound!"; - } - XirInstruction[] fp = fastPath.toArray(new XirInstruction[fastPath.size()]); - XirInstruction[] sp = slowPath.size() > 0 ? slowPath.toArray(new XirInstruction[slowPath.size()]) : null; - XirLabel[] xirLabels = labels.toArray(new XirLabel[labels.size()]); - XirParameter[] xirParameters = parameters.toArray(new XirParameter[parameters.size()]); - XirTemp[] temporaryOperands = temps.toArray(new XirTemp[temps.size()]); - XirConstant[] constantOperands = constants.toArray(new XirConstant[constants.size()]); - XirTemplate[] calleeTemplateArray = calleeTemplates.toArray(new XirTemplate[calleeTemplates.size()]); - XirMark[] marksArray = marks.toArray(new XirMark[marks.size()]); - return new XirTemplate(name, this.variableCount, this.allocateResultOperand, resultOperand, fp, sp, xirLabels, xirParameters, temporaryOperands, constantOperands, flags, calleeTemplateArray, marksArray, outgoingStackSize); - } - - @Override - public CiXirAssembler copy() { - return new AMD64XirAssembler(); - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/util/ArrayMap.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/util/ArrayMap.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,117 +0,0 @@ -/* - * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.util; - -/** - * The {@code ArrayMap} class implements an efficient one-level map which is implemented - * as an array. Note that because of the one-level array inside, this data structure performs best - * when the range of integer keys is small and densely used. Note that the implementation can - * handle arbitrary intervals, including negative numbers, up to intervals of size 2^31 - 1. - * - * @author Ben L. Titzer - */ -public class ArrayMap { - - private static final int INITIAL_SIZE = 5; // how big the initial array should be - private static final int EXTRA = 2; // how far on the left or right of a new element to grow - - Object[] map; - int low; - - /** - * Constructs a new {@code ArrayMap} with no initial assumptions. - */ - public ArrayMap() { - } - - /** - * Constructs a new {@code ArrayMap} that initially covers the specified interval. - * Note that this map will automatically expand if necessary later. - * @param low the low index, inclusive - * @param high the high index, exclusive - */ - public ArrayMap(int low, int high) { - this.low = low; - this.map = new Object[high - low + 1]; - } - - /** - * Puts a new value in the map at the specified index. - * @param i the index at which to store the value - * @param value the value to store at the specified index - */ - public void put(int i, T value) { - int index = i - low; - if (map == null) { - // no map yet - map = new Object[INITIAL_SIZE]; - low = index - 2; - map[INITIAL_SIZE / 2] = value; - } else if (index < 0) { - // grow backwards - growBackward(i, value); - } else if (index >= map.length) { - // grow forwards - growForward(i, value); - } else { - // no growth necessary - map[index] = value; - } - } - - /** - * Gets the value at the specified index in the map. - * @param i the index - * @return the value at the specified index; {@code null} if there is no value at the specified index, - * or if the index is out of the currently stored range - */ - public T get(int i) { - int index = i - low; - if (map == null || index < 0 || index >= map.length) { - return null; - } - Class type = null; - return Util.uncheckedCast(type, map[index]); - } - - public int length() { - return map.length; - } - - private void growBackward(int i, T value) { - int nlow = i - EXTRA; - Object[] nmap = new Object[low - nlow + map.length]; - System.arraycopy(map, 0, nmap, low - nlow, map.length); - map = nmap; - low = nlow; - map[i - low] = value; - } - - private void growForward(int i, T value) { - int nlen = i - low + 1 + EXTRA; - Object[] nmap = new Object[nlen]; - System.arraycopy(map, 0, nmap, 0, map.length); - map = nmap; - map[i - low] = value; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/util/BitMap2D.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/util/BitMap2D.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,102 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.util; - -import com.sun.cri.ci.*; - -/** - * This class implements a two-dimensional bitmap. - * - * @author Marcelo Cintra - * @author Thomas Wuerthinger - */ -public final class BitMap2D { - - private CiBitMap map; - private final int bitsPerSlot; - - private int bitIndex(int slotIndex, int bitWithinSlotIndex) { - return slotIndex * bitsPerSlot + bitWithinSlotIndex; - } - - private boolean verifyBitWithinSlotIndex(int index) { - assert index < bitsPerSlot : "index " + index + " is out of bounds " + bitsPerSlot; - return true; - } - - public BitMap2D(int sizeInSlots, int bitsPerSlot) { - map = new CiBitMap(sizeInSlots * bitsPerSlot); - this.bitsPerSlot = bitsPerSlot; - } - - public int sizeInBits() { - return map.size(); - } - - // Returns number of full slots that have been allocated - public int sizeInSlots() { - return map.size() / bitsPerSlot; - } - - public boolean isValidIndex(int slotIndex, int bitWithinSlotIndex) { - assert verifyBitWithinSlotIndex(bitWithinSlotIndex); - return (bitIndex(slotIndex, bitWithinSlotIndex) < sizeInBits()); - } - - public boolean at(int slotIndex, int bitWithinSlotIndex) { - assert verifyBitWithinSlotIndex(bitWithinSlotIndex); - return map.get(bitIndex(slotIndex, bitWithinSlotIndex)); - } - - public void setBit(int slotIndex, int bitWithinSlotIndex) { - assert verifyBitWithinSlotIndex(bitWithinSlotIndex); - map.set(bitIndex(slotIndex, bitWithinSlotIndex)); - } - - public void clearBit(int slotIndex, int bitWithinSlotIndex) { - assert verifyBitWithinSlotIndex(bitWithinSlotIndex); - map.clear(bitIndex(slotIndex, bitWithinSlotIndex)); - } - - public void atPutGrow(int slotIndex, int bitWithinSlotIndex, boolean value) { - int size = sizeInSlots(); - if (size <= slotIndex) { - while (size <= slotIndex) { - size *= 2; - } - CiBitMap newBitMap = new CiBitMap(size * bitsPerSlot); - newBitMap.setUnion(map); - map = newBitMap; - } - - if (value) { - setBit(slotIndex, bitWithinSlotIndex); - } else { - clearBit(slotIndex, bitWithinSlotIndex); - } - } - - public void clear() { - map.clearAll(); - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/util/BlockWorkList.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/util/BlockWorkList.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,129 +0,0 @@ -/* - * Copyright (c) 2009, 2009, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.util; - -import com.sun.c1x.ir.*; - -/** - * This class implements a worklist for dealing with blocks. The worklist can - * operate either as a stack (i.e. first-in / last-out), or as a sorted list, - * where blocks can be sorted by a supplied number. The latter usage lends itself - * naturally to iterative dataflow analysis problems. - * - * This implementation is not able to tell if a block is in the worklist already. - * Note that this implementation is slightly less efficient than the dedicated - * work list in {@link com.sun.c1x.graph.ScopeData}, because this worklist uses - * an externally supplied number. - * - * @author Ben L. Titzer - */ -public class BlockWorkList { - Merge[] workList; - int[] workListNumbers; - int workListIndex; - - /** - * Adds a block to this list in an unsorted fashion, like a stack. - * @param block the block to add - */ - public void add(Merge block) { - if (workList == null) { - // worklist not allocated yet - allocate(); - } else if (workListIndex == workList.length) { - // need to grow the worklist - grow(); - } - // put the block at the end of the array - workList[workListIndex++] = block; - } - - /** - * Adds a block to this list, sorted by the supplied number. The block - * with the lowest number is returned upon subsequent removes. - * @param block the block to add - * @param number the number used to sort the block - */ - public void addSorted(Merge block, int number) { - if (workList == null) { - // worklist not allocated yet - allocate(); - } else if (workListIndex == workList.length) { - // need to grow the worklist - grow(); - } - // put the block at the end of the array - workList[workListIndex] = block; - workListNumbers[workListIndex] = number; - workListIndex++; - int i = workListIndex - 2; - // push block towards the beginning of the array - for (; i >= 0; i--) { - int n = workListNumbers[i]; - if (n >= number) { - break; // already in the right position - } - workList[i + 1] = workList[i]; // bubble b down by one - workList[i] = block; // and overwrite its place with block - workListNumbers[i + 1] = n; // bubble n down by one - workListNumbers[i] = number; // and overwrite its place with number - } - } - - /** - * Removes the next block from this work list. If the blocks have been added - * in a sorted order, then the block with the lowest number is returned. Otherwise, - * the last block added is returned. - * @return the next block in the list - */ - public Merge removeFromWorkList() { - if (workListIndex != 0) { - return workList[--workListIndex]; - } - return null; - } - - /** - * Checks whether the list is empty. - * @return {@code true} if this list is empty - */ - public boolean isEmpty() { - return workListIndex == 0; - } - - private void allocate() { - workList = new Merge[5]; - workListNumbers = new int[5]; - } - - private void grow() { - int prevLength = workList.length; - Merge[] nworkList = new Merge[prevLength * 3]; - System.arraycopy(workList, 0, nworkList, 0, prevLength); - workList = nworkList; - - int[] nworkListNumbers = new int[prevLength * 3]; - System.arraycopy(workListNumbers, 0, nworkListNumbers, 0, prevLength); - workListNumbers = nworkListNumbers; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/util/IntList.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/util/IntList.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,163 +0,0 @@ -/* - * Copyright (c) 2010, 2010, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.util; - -import java.util.*; - -/** - * An expandable and indexable list of {@code int}s. - * - * This class avoids the boxing/unboxing incurred by {@code ArrayList}. - * - * @author Doug Simon - */ -public final class IntList { - - private int[] array; - private int size; - - /** - * Creates an int list with a specified initial capacity. - * - * @param initialCapacity - */ - public IntList(int initialCapacity) { - array = new int[initialCapacity]; - } - - /** - * Creates an int list with a specified initial array. - * - * @param array the initial array used for the list (no copy is made) - * @param initialSize the initial {@linkplain #size() size} of the list (must be less than or equal to {@code array.length} - */ - public IntList(int[] array, int initialSize) { - assert initialSize <= array.length; - this.array = array; - this.size = initialSize; - } - - /** - * Makes a new int list by copying a range from a given int list. - * - * @param other the list from which a range of values is to be copied into the new list - * @param startIndex the index in {@code other} at which to start copying - * @param length the number of values to copy from {@code other} - * @return a new int list whose {@linkplain #size() size} and capacity is {@code length} - */ - public static IntList copy(IntList other, int startIndex, int length) { - return copy(other, startIndex, length, length); - } - - /** - * Makes a new int list by copying a range from a given int list. - * - * @param other the list from which a range of values is to be copied into the new list - * @param startIndex the index in {@code other} at which to start copying - * @param length the number of values to copy from {@code other} - * @param initialCapacity the initial capacity of the new int list (must be greater or equal to {@code length}) - * @return a new int list whose {@linkplain #size() size} is {@code length} - */ - public static IntList copy(IntList other, int startIndex, int length, int initialCapacity) { - assert initialCapacity >= length : "initialCapacity < length"; - int[] array = new int[initialCapacity]; - System.arraycopy(other.array, startIndex, array, 0, length); - return new IntList(array, length); - } - - public int size() { - return size; - } - - /** - * Appends a value to the end of this list, increasing its {@linkplain #size() size} by 1. - * - * @param value the value to append - */ - public void add(int value) { - if (size == array.length) { - int newSize = (size * 3) / 2 + 1; - array = Arrays.copyOf(array, newSize); - } - array[size++] = value; - } - - /** - * Gets the value in this list at a given index. - * - * @param index the index of the element to return - * @throws IndexOutOfBoundsException if {@code index < 0 || index >= size()} - */ - public int get(int index) { - if (index >= size) { - throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size); - } - return array[index]; - } - - /** - * Sets the size of this list to 0. - */ - public void clear() { - size = 0; - } - - /** - * Sets a value at a given index in this list. - * - * @param index the index of the element to update - * @param value the new value of the element - * @throws IndexOutOfBoundsException if {@code index < 0 || index >= size()} - */ - public void set(int index, int value) { - if (index >= size) { - throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size); - } - array[index] = value; - } - - /** - * Adjusts the {@linkplain #size() size} of this int list. - * - * If {@code newSize < size()}, the size is changed to {@code newSize}. - * If {@code newSize > size()}, sufficient 0 elements are {@linkplain #add(int) added} - * until {@code size() == newSize}. - * - * @param newSize the new size of this int list - */ - public void setSize(int newSize) { - if (newSize < size) { - size = newSize; - } else if (newSize > size) { - array = Arrays.copyOf(array, newSize); - } - } - - @Override - public String toString() { - if (array.length == size) { - return Arrays.toString(array); - } - return Arrays.toString(Arrays.copyOf(array, size)); - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/util/Util.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/util/Util.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,427 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.util; - -import java.util.*; - -import com.sun.c1x.*; -import com.sun.c1x.debug.*; -import com.sun.c1x.ir.*; -import com.sun.cri.ci.*; -import com.sun.cri.ri.*; - -/** - * The {@code Util} class contains a motley collection of utility methods used throughout the compiler. - * - * @author Ben L. Titzer - * @author Doug Simon - */ -public class Util { - - public static final int PRINTING_LINE_WIDTH = 40; - public static final char SECTION_CHARACTER = '*'; - public static final char SUB_SECTION_CHARACTER = '='; - public static final char SEPERATOR_CHARACTER = '-'; - - public static RuntimeException unimplemented() { - throw new InternalError("unimplemented"); - } - - public static RuntimeException unimplemented(String msg) { - throw new InternalError("unimplemented:" + msg); - } - - public static RuntimeException shouldNotReachHere() { - throw new InternalError("should not reach here"); - } - - public static RuntimeException shouldNotReachHere(String msg) { - throw new InternalError("Should not reach here: " + msg); - } - - public static boolean replaceInList(T a, T b, List list) { - final int max = list.size(); - for (int i = 0; i < max; i++) { - if (list.get(i) == a) { - list.set(i, b); - return true; - } - } - return false; - } - - public static boolean replaceAllInList(T a, T b, List list) { - final int max = list.size(); - for (int i = 0; i < max; i++) { - if (list.get(i) == a) { - list.set(i, b); - } - } - return false; - } - - /** - * Statically cast an object to an arbitrary Object type. Dynamically checked. - */ - @SuppressWarnings("unchecked") - public static T uncheckedCast(Class type, Object object) { - return (T) object; - } - - /** - * Statically cast an object to an arbitrary Object type. Dynamically checked. - */ - @SuppressWarnings("unchecked") - public static T uncheckedCast(Object object) { - return (T) object; - } - - /** - * Utility method to combine a base hash with the identity hash of one or more objects. - * - * @param hash the base hash - * @param x the object to add to the hash - * @return the combined hash - */ - public static int hash1(int hash, Object x) { - // always set at least one bit in case the hash wraps to zero - return 0x10000000 | (hash + 7 * System.identityHashCode(x)); - } - - /** - * Utility method to combine a base hash with the identity hash of one or more objects. - * - * @param hash the base hash - * @param x the first object to add to the hash - * @param y the second object to add to the hash - * @return the combined hash - */ - public static int hash2(int hash, Object x, Object y) { - // always set at least one bit in case the hash wraps to zero - return 0x20000000 | (hash + 7 * System.identityHashCode(x) + 11 * System.identityHashCode(y)); - } - - /** - * Utility method to combine a base hash with the identity hash of one or more objects. - * - * @param hash the base hash - * @param x the first object to add to the hash - * @param y the second object to add to the hash - * @param z the third object to add to the hash - * @return the combined hash - */ - public static int hash3(int hash, Object x, Object y, Object z) { - // always set at least one bit in case the hash wraps to zero - return 0x30000000 | (hash + 7 * System.identityHashCode(x) + 11 * System.identityHashCode(y) + 13 * System.identityHashCode(z)); - } - - /** - * Utility method to combine a base hash with the identity hash of one or more objects. - * - * @param hash the base hash - * @param x the first object to add to the hash - * @param y the second object to add to the hash - * @param z the third object to add to the hash - * @param w the fourth object to add to the hash - * @return the combined hash - */ - public static int hash4(int hash, Object x, Object y, Object z, Object w) { - // always set at least one bit in case the hash wraps to zero - return 0x40000000 | (hash + 7 * System.identityHashCode(x) + 11 * System.identityHashCode(y) + 13 * System.identityHashCode(z) + 17 * System.identityHashCode(w)); - } - - static { - assert CiUtil.log2(2) == 1; - assert CiUtil.log2(4) == 2; - assert CiUtil.log2(8) == 3; - assert CiUtil.log2(16) == 4; - assert CiUtil.log2(32) == 5; - assert CiUtil.log2(0x40000000) == 30; - - assert CiUtil.log2(2L) == 1; - assert CiUtil.log2(4L) == 2; - assert CiUtil.log2(8L) == 3; - assert CiUtil.log2(16L) == 4; - assert CiUtil.log2(32L) == 5; - assert CiUtil.log2(0x4000000000000000L) == 62; - - assert !CiUtil.isPowerOf2(3); - assert !CiUtil.isPowerOf2(5); - assert !CiUtil.isPowerOf2(7); - assert !CiUtil.isPowerOf2(-1); - - assert CiUtil.isPowerOf2(2); - assert CiUtil.isPowerOf2(4); - assert CiUtil.isPowerOf2(8); - assert CiUtil.isPowerOf2(16); - assert CiUtil.isPowerOf2(32); - assert CiUtil.isPowerOf2(64); - } - - /** - * Sets the element at a given position of a list and ensures that this position exists. If the list is current - * shorter than the position, intermediate positions are filled with a given value. - * - * @param list the list to put the element into - * @param pos the position at which to insert the element - * @param x the element that should be inserted - * @param filler the filler element that is used for the intermediate positions in case the list is shorter than pos - */ - public static void atPutGrow(List list, int pos, T x, T filler) { - if (list.size() < pos + 1) { - while (list.size() < pos + 1) { - list.add(filler); - } - assert list.size() == pos + 1; - } - - assert list.size() >= pos + 1; - list.set(pos, x); - } - - public static void breakpoint() { - // do nothing. - } - - public static void guarantee(boolean b, String string) { - if (!b) { - throw new CiBailout(string); - } - } - - public static void warning(String string) { - TTY.println("WARNING: " + string); - } - - public static int safeToInt(long l) { - assert (int) l == l; - return (int) l; - } - - public static int roundUp(int number, int mod) { - return ((number + mod - 1) / mod) * mod; - } - - public static void truncate(List list, int length) { - while (list.size() > length) { - list.remove(list.size() - 1); - } - } - - public static void printSection(String name, char sectionCharacter) { - - String header = " " + name + " "; - int remainingCharacters = PRINTING_LINE_WIDTH - header.length(); - int leftPart = remainingCharacters / 2; - int rightPart = remainingCharacters - leftPart; - for (int i = 0; i < leftPart; i++) { - TTY.print(sectionCharacter); - } - - TTY.print(header); - - for (int i = 0; i < rightPart; i++) { - TTY.print(sectionCharacter); - } - - TTY.println(); - } - - /** - * Prints entries in a byte array as space separated hex values to {@link TTY}. - * - * @param address an address at which the bytes are located. This is used to print an address prefix per line of output. - * @param array the array containing all the bytes to print - * @param bytesPerLine the number of values to print per line of output - */ - public static void printBytes(long address, byte[] array, int bytesPerLine) { - printBytes(address, array, 0, array.length, bytesPerLine); - } - - /** - * Prints entries in a byte array as space separated hex values to {@link TTY}. - * - * @param address an address at which the bytes are located. This is used to print an address prefix per line of output. - * @param array the array containing the bytes to print - * @param offset the offset in {@code array} of the values to print - * @param length the number of values from {@code array} print - * @param bytesPerLine the number of values to print per line of output - */ - public static void printBytes(long address, byte[] array, int offset, int length, int bytesPerLine) { - assert bytesPerLine > 0; - boolean newLine = true; - for (int i = 0; i < length; i++) { - if (newLine) { - TTY.print("%08x: ", address + i); - newLine = false; - } - TTY.print("%02x ", array[i]); - if (i % bytesPerLine == bytesPerLine - 1) { - TTY.println(); - newLine = true; - } - } - - if (length % bytesPerLine != bytesPerLine) { - TTY.println(); - } - } - - public static CiKind[] signatureToKinds(RiSignature signature, CiKind receiverKind) { - int args = signature.argumentCount(false); - CiKind[] result; - int i = 0; - if (receiverKind != null) { - result = new CiKind[args + 1]; - result[0] = receiverKind; - i = 1; - } else { - result = new CiKind[args]; - } - for (int j = 0; j < args; j++) { - result[i + j] = signature.argumentKindAt(j); - } - return result; - } - - public static boolean isShiftCount(int x) { - return 0 <= x && x < 32; - } - - /** - * Determines if a given {@code int} value is the range of unsigned byte values. - */ - public static boolean isUByte(int x) { - return (x & 0xff) == x; - } - - /** - * Determines if a given {@code int} value is the range of signed byte values. - */ - public static boolean isByte(int x) { - return (byte) x == x; - } - - /** - * Determines if a given {@code long} value is the range of unsigned byte values. - */ - public static boolean isUByte(long x) { - return (x & 0xffL) == x; - } - - /** - * Determines if a given {@code long} value is the range of signed byte values. - */ - public static boolean isByte(long l) { - return (byte) l == l; - } - - /** - * Determines if a given {@code long} value is the range of unsigned int values. - */ - public static boolean isUInt(long x) { - return (x & 0xffffffffL) == x; - } - - /** - * Determines if a given {@code long} value is the range of signed int values. - */ - public static boolean isInt(long l) { - return (int) l == l; - } - /** - * Determines if a given {@code int} value is the range of signed short values. - */ - public static boolean isShort(int x) { - return (short) x == x; - } - - public static boolean is32bit(long x) { - return -0x80000000L <= x && x < 0x80000000L; - } - - public static short safeToShort(int v) { - assert isShort(v); - return (short) v; - } - - /** - * Determines if the kinds of two given IR nodes are equal at the {@linkplain #archKind(CiKind) architecture} - * level in the context of the {@linkplain C1XCompilation#compilation()} compilation. - */ - public static boolean archKindsEqual(Value i, Value other) { - return archKindsEqual(i.kind, other.kind); - } - - /** - * Determines if two given kinds are equal at the {@linkplain #archKind(CiKind) architecture} level - * in the context of the {@linkplain C1XCompilation#compilation()} compilation. - */ - public static boolean archKindsEqual(CiKind k1, CiKind k2) { - C1XCompilation compilation = C1XCompilation.compilation(); - assert compilation != null : "missing compilation context"; - return compilation.archKindsEqual(k1, k2); - } - - /** - * Translates a given kind to a {@linkplain C1XCompilation#archKind(CiKind) canonical architecture} - * kind in the context of the {@linkplain C1XCompilation#compilation() current} compilation. - */ - public static CiKind archKind(CiKind kind) { - C1XCompilation compilation = C1XCompilation.compilation(); - assert compilation != null : "missing compilation context"; - return compilation.archKind(kind); - } - - - /** - * Checks that two instructions are equivalent, optionally comparing constants. - * @param x the first instruction - * @param y the second instruction - * @param compareConstants {@code true} if equivalent constants should be considered equivalent - * @return {@code true} if the instructions are equivalent; {@code false} otherwise - */ - public static boolean equivalent(Instruction x, Instruction y, boolean compareConstants) { - if (x == y) { - return true; - } - if (compareConstants && x != null && y != null) { - if (x.isConstant() && x.asConstant().equivalent(y.asConstant())) { - return true; - } - } - return false; - } - - /** - * Converts a given instruction to a value string. The representation of an instruction as - * a value is formed by concatenating the {@linkplain com.sun.cri.ci.CiKind#typeChar character} denoting its - * {@linkplain Value#kind kind} and its {@linkplain Value#id()}. For example, {@code "i13"}. - * - * @param value the instruction to convert to a value string. If {@code value == null}, then "-" is returned. - * @return the instruction representation as a string - */ - public static String valueString(Value value) { - return (value == null) ? "-" : ("" + value.kind.typeChar + value.id()); - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/value/FrameState.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/value/FrameState.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,516 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.value; - -import static com.sun.c1x.value.ValueUtil.*; - -import java.util.*; - -import com.oracle.graal.graph.*; -import com.sun.c1x.*; -import com.sun.c1x.debug.*; -import com.sun.c1x.ir.*; -import com.sun.cri.ci.*; -import com.sun.cri.ri.*; - -/** - * The {@code FrameState} class encapsulates the frame state (i.e. local variables and - * operand stack) at a particular point in the abstract interpretation. - */ -public final class FrameState extends Value implements FrameStateAccess { - - private static final int INPUT_COUNT = 1; - - private static final int INPUT_OUTER_FRAME_STATE = 0; - - protected final int localsSize; - - protected final int stackSize; - - protected final int locksSize; - - private static final int SUCCESSOR_COUNT = 0; - - @Override - protected int inputCount() { - return super.inputCount() + localsSize + stackSize + locksSize; - } - - @Override - protected int successorCount() { - return super.successorCount() + SUCCESSOR_COUNT; - } - - public FrameState outerFrameState() { - return (FrameState) inputs().get(super.inputCount() + INPUT_OUTER_FRAME_STATE); - } - - public FrameState setOuterFrameState(FrameState n) { - return (FrameState) inputs().set(super.inputCount() + INPUT_OUTER_FRAME_STATE, n); - } - - @Override - public void setValueAt(int i, Value x) { - inputs().set(INPUT_COUNT + i, x); - } - - /** - * The bytecode index to which this frame state applies. This will be {@code -1} - * iff this state is mutable. - */ - public final int bci; - - public final RiMethod method; - - /** - * Creates a {@code FrameState} for the given scope and maximum number of stack and local variables. - * - * @param bci the bytecode index of the frame state - * @param localsSize number of locals - * @param stackSize size of the stack - * @param lockSize number of locks - */ - public FrameState(RiMethod method, int bci, int localsSize, int stackSize, int locksSize, Graph graph) { - super(CiKind.Illegal, localsSize + stackSize + locksSize + INPUT_COUNT, SUCCESSOR_COUNT, graph); - this.method = method; - this.bci = bci; - this.localsSize = localsSize; - this.stackSize = stackSize; - this.locksSize = locksSize; - C1XMetrics.FrameStatesCreated++; - C1XMetrics.FrameStateValuesCreated += localsSize + stackSize + locksSize; - } - - FrameState(RiMethod method, int bci, Value[] locals, Value[] stack, int stackSize, ArrayList locks, Graph graph) { - this(method, bci, locals.length, stackSize, locks.size(), graph); - for (int i = 0; i < locals.length; i++) { - setValueAt(i, locals[i]); - } - for (int i = 0; i < stackSize; i++) { - setValueAt(localsSize + i, stack[i]); - } - for (int i = 0; i < locks.size(); i++) { - setValueAt(locals.length + stackSize + i, locks.get(i)); - } - } - - /** - * Gets a copy of this frame state. - */ - public FrameState duplicate(int bci) { - FrameState other = copy(bci); - other.inputs().setAll(inputs()); - return other; - } - - /** - * Gets a copy of this frame state without the stack. - */ - @Override - public FrameState duplicateWithEmptyStack(int bci) { - FrameState other = new FrameState(method, bci, localsSize, 0, locksSize(), graph()); - for (int i = 0; i < localsSize; i++) { - other.setValueAt(i, localAt(i)); - } - for (int i = 0; i < locksSize; i++) { - other.setValueAt(localsSize + i, lockAt(i)); - } - other.setOuterFrameState(outerFrameState()); - return other; - } - - /** - * Creates a copy of this frame state with one stack element of type popKind popped from the stack and the - * values in pushedValues pushed on the stack. The pushedValues are expected to be in slot encoding: a long - * or double is followed by a null slot. - */ - public FrameState duplicateModified(int bci, CiKind popKind, Value... pushedValues) { - int popSlots = popKind.sizeInSlots(); - int pushSlots = pushedValues.length; - FrameState other = new FrameState(method, bci, localsSize, stackSize - popSlots + pushSlots, locksSize(), graph()); - for (int i = 0; i < localsSize; i++) { - other.setValueAt(i, localAt(i)); - } - for (int i = 0; i < stackSize - popSlots; i++) { - other.setValueAt(localsSize + i, stackAt(i)); - } - int slot = localsSize + stackSize - popSlots; - for (int i = 0; i < pushSlots; i++) { - other.setValueAt(slot++, pushedValues[i]); - } - for (int i = 0; i < locksSize; i++) { - other.setValueAt(localsSize + other.stackSize + i, lockAt(i)); - } - other.setOuterFrameState(outerFrameState()); - return other; - } - - public boolean isCompatibleWith(FrameStateAccess other) { - if (stackSize() != other.stackSize() || localsSize() != other.localsSize() || locksSize() != other.locksSize()) { - return false; - } - for (int i = 0; i < stackSize(); i++) { - Value x = stackAt(i); - Value y = other.stackAt(i); - if (x != y && typeMismatch(x, y)) { - return false; - } - } - for (int i = 0; i < locksSize(); i++) { - if (lockAt(i) != other.lockAt(i)) { - return false; - } - } - if (other.outerFrameState() != outerFrameState()) { - return false; - } - return true; - } - - /** - * Gets the size of the local variables. - */ - public int localsSize() { - return localsSize; - } - - /** - * Gets the current size (height) of the stack. - */ - public int stackSize() { - return stackSize; - } - - /** - * Gets number of locks held by this frame state. - */ - public int locksSize() { - return locksSize; - } - - /** - * Invalidates the local variable at the specified index. If the specified index refers to a doubleword local, then - * invalidates the high word as well. - * - * @param i the index of the local to invalidate - */ - public void invalidateLocal(int i) { - // note that for double word locals, the high slot should already be null - // unless the local is actually dead and the high slot is being reused; - // in either case, it is not necessary to null the high slot - setValueAt(i, null); - } - - /** - * Stores a given local variable at the specified index. If the value is a {@linkplain CiKind#isDoubleWord() double word}, - * then the next local variable index is also overwritten. - * - * @param i the index at which to store - * @param x the instruction which produces the value for the local - */ - public void storeLocal(int i, Value x) { - assert i < localsSize : "local variable index out of range: " + i; - invalidateLocal(i); - setValueAt(i, x); - if (isDoubleWord(x)) { - // (tw) if this was a double word then kill i+1 - setValueAt(i + 1, null); - } - if (i > 0) { - // if there was a double word at i - 1, then kill it - Value p = localAt(i - 1); - if (isDoubleWord(p)) { - setValueAt(i - 1, null); - } - } - } - - /** - * Gets the value in the local variables at the specified index. - * - * @param i the index into the locals - * @return the instruction that produced the value for the specified local - */ - public Value localAt(int i) { - assert i < localsSize : "local variable index out of range: " + i; - return valueAt(i); - } - - /** - * Get the value on the stack at the specified stack index. - * - * @param i the index into the stack, with {@code 0} being the bottom of the stack - * @return the instruction at the specified position in the stack - */ - public Value stackAt(int i) { - assert i >= 0 && i < (localsSize + stackSize); - return valueAt(localsSize + i); - } - - /** - * Retrieves the lock at the specified index in the lock stack. - * @param i the index into the lock stack - * @return the instruction which produced the object at the specified location in the lock stack - */ - public Value lockAt(int i) { - assert i >= 0; - return valueAt(localsSize + stackSize + i); - } - - /** - * Inserts a phi statement into the stack at the specified stack index. - * @param block the block begin for which we are creating the phi - * @param i the index into the stack for which to create a phi - */ - public Phi setupPhiForStack(Merge block, int i) { - Value p = stackAt(i); - if (p != null) { - if (p instanceof Phi) { - Phi phi = (Phi) p; - if (phi.block() == block) { - return phi; - } - } - Phi phi = new Phi(p.kind, block, graph()); - setValueAt(localsSize + i, phi); - return phi; - } - return null; - } - - /** - * Inserts a phi statement for the local at the specified index. - * @param block the block begin for which we are creating the phi - * @param i the index of the local variable for which to create the phi - */ - public Phi setupPhiForLocal(Merge block, int i) { - Value p = localAt(i); - if (p instanceof Phi) { - Phi phi = (Phi) p; - if (phi.block() == block) { - return phi; - } - } - Phi phi = new Phi(p.kind, block, graph()); - storeLocal(i, phi); - return phi; - } - - /** - * Gets the value at a specified index in the set of operand stack and local values represented by this frame. - * This method should only be used to iterate over all the values in this frame, irrespective of whether - * they are on the stack or in local variables. - * To iterate the stack slots, the {@link #stackAt(int)} and {@link #stackSize()} methods should be used. - * To iterate the local variables, the {@link #localAt(int)} and {@link #localsSize()} methods should be used. - * - * @param i a value in the range {@code [0 .. valuesSize()]} - * @return the value at index {@code i} which may be {@code null} - */ - public Value valueAt(int i) { - assert i < (localsSize + stackSize + locksSize); - return (Value) inputs().get(INPUT_COUNT + i); - } - - /** - * The number of operand stack slots and local variables in this frame. - * This method should typically only be used in conjunction with {@link #valueAt(int)}. - * To iterate the stack slots, the {@link #stackAt(int)} and {@link #stackSize()} methods should be used. - * To iterate the local variables, the {@link #localAt(int)} and {@link #localsSize()} methods should be used. - * - * @return the number of local variables in this frame - */ - public int valuesSize() { - return localsSize + stackSize; - } - - private void checkSize(FrameStateAccess other) { - if (other.stackSize() != stackSize()) { - throw new CiBailout("stack sizes do not match"); - } else if (other.localsSize() != localsSize) { - throw new CiBailout("local sizes do not match"); - } - } - - public void merge(Merge block, FrameStateAccess other) { - checkSize(other); - for (int i = 0; i < valuesSize(); i++) { - Value x = valueAt(i); - if (x != null) { - Value y = other.valueAt(i); - if (x != y || ((x instanceof Phi) && ((Phi) x).block() == block)) { - if (typeMismatch(x, y)) { - if (x instanceof Phi) { - Phi phi = (Phi) x; - if (phi.block() == block) { - phi.makeDead(); - } - } - setValueAt(i, null); - continue; - } - Phi phi = null; - if (i < localsSize) { - // this a local - phi = setupPhiForLocal(block, i); - } else { - // this is a stack slot - phi = setupPhiForStack(block, i - localsSize); - } - - Phi originalPhi = phi; - if (phi.valueCount() == 0) { - int size = block.predecessors().size(); - for (int j = 0; j < size; ++j) { - phi = phi.addInput(x); - } - phi = phi.addInput((x == y) ? phi : y); - } else { - phi = phi.addInput((x == y) ? phi : y); - } - if (originalPhi != phi) { - for (int j = 0; j < other.localsSize() + other.stackSize(); ++j) { - if (other.valueAt(j) == originalPhi) { - other.setValueAt(j, phi); - } - } - } - - if (block instanceof LoopBegin) { -// assert phi.valueCount() == ((LoopBegin) block).loopEnd().predecessors().size() + 1 : "loop, valueCount=" + phi.valueCount() + " predSize= " + ((LoopBegin) block).loopEnd().predecessors().size(); - } else { - assert phi.valueCount() == block.predecessors().size() + 1 : "valueCount=" + phi.valueCount() + " predSize= " + block.predecessors().size(); - } - } - } - } - } - - public Merge block() { - for (Node usage : usages()) { - if (usage instanceof Merge) { - return (Merge) usage; - } - } - return null; - } - - /** - * The interface implemented by a client of {@link FrameState#forEachPhi(Merge, PhiProcedure)} and - * {@link FrameState#forEachLivePhi(Merge, PhiProcedure)}. - */ - public static interface PhiProcedure { - boolean doPhi(Phi phi); - } - - /** - * Checks whether this frame state has any {@linkplain Phi phi} statements. - */ - public boolean hasPhis() { - for (int i = 0; i < valuesSize(); i++) { - Value value = valueAt(i); - if (value instanceof Phi) { - return true; - } - } - return false; - } - - /** - * The interface implemented by a client of {@link FrameState#forEachLiveStateValue(ValueProcedure)}. - */ - public static interface ValueProcedure { - void doValue(Value value); - } - - /** - * Traverses all {@linkplain Value#isLive() live values} of this frame state. - * - * @param proc the call back called to process each live value traversed - */ - public void forEachLiveStateValue(ValueProcedure proc) { - for (int i = 0; i < valuesSize(); i++) { - Value value = valueAt(i); - if (value != null) { - proc.doValue(value); - } - } - if (outerFrameState() != null) { - outerFrameState().forEachLiveStateValue(proc); - } - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - String nl = String.format("%n"); - sb.append("[bci: ").append(bci).append("]").append(nl); - for (int i = 0; i < localsSize(); ++i) { - Value value = localAt(i); - sb.append(String.format(" local[%d] = %-8s : %s%n", i, value == null ? "bogus" : value.kind.javaName, value)); - } - for (int i = 0; i < stackSize(); ++i) { - Value value = stackAt(i); - sb.append(String.format(" stack[%d] = %-8s : %s%n", i, value == null ? "bogus" : value.kind.javaName, value)); - } - for (int i = 0; i < locksSize(); ++i) { - Value value = lockAt(i); - sb.append(String.format(" lock[%d] = %-8s : %s%n", i, value == null ? "bogus" : value.kind.javaName, value)); - } - return sb.toString(); - } - - @Override - public void accept(ValueVisitor v) { - v.visitFrameState(this); - } - - @Override - public void print(LogStream out) { - out.print("FrameState"); - } - - @Override - public FrameState copy() { - return new FrameState(method, bci, localsSize, stackSize, locksSize, graph()); - } - - - private FrameState copy(int newBci) { - return new FrameState(method, newBci, localsSize, stackSize, locksSize, graph()); - } - - @Override - public String shortName() { - return "FrameState@" + bci; - } - - public void visitFrameState(FrameState i) { - // nothing to do for now - } - - @Override - public Node copy(Graph into) { - FrameState x = new FrameState(method, bci, localsSize, stackSize, locksSize, into); - return x; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/value/FrameStateAccess.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/value/FrameStateAccess.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.value; - -import com.sun.c1x.ir.*; - -public interface FrameStateAccess { - - FrameState duplicate(int newBci); - - int localsSize(); - - int stackSize(); - - int locksSize(); - - Value valueAt(int i); - - Value localAt(int i); - - Value lockAt(int i); - - Value stackAt(int i); - - FrameState duplicateWithEmptyStack(int bci); - - void setValueAt(int j, Value v); - - Value outerFrameState(); - -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/value/FrameStateBuilder.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/value/FrameStateBuilder.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,507 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.value; - -import static com.sun.c1x.value.ValueUtil.*; -import static java.lang.reflect.Modifier.*; - -import java.util.*; - -import com.oracle.graal.graph.*; -import com.sun.c1x.ir.*; -import com.sun.cri.ci.*; -import com.sun.cri.ri.*; - - -public class FrameStateBuilder implements FrameStateAccess { - - private final Graph graph; - - private final Value[] locals; - private final Value[] stack; - private final ArrayList locks; - - private int stackIndex; - - private final RiMethod method; - - public FrameStateBuilder(RiMethod method, Graph graph) { - this.method = method; - this.graph = graph; - this.locals = new Value[method.maxLocals()]; - // we always need at least one stack slot (for exceptions) - int stackSize = Math.max(1, method.maxStackSize()); - this.stack = new Value[stackSize]; - - int javaIndex = 0; - int index = 0; - if (!isStatic(method.accessFlags())) { - // add the receiver and assume it is non null - Local local = new Local(method.holder().kind(), javaIndex, graph); - local.inputs().set(0, graph.start()); - local.setDeclaredType(method.holder()); - storeLocal(javaIndex, local); - javaIndex = 1; - index = 1; - } - RiSignature sig = method.signature(); - int max = sig.argumentCount(false); - RiType accessingClass = method.holder(); - for (int i = 0; i < max; i++) { - RiType type = sig.argumentTypeAt(i, accessingClass); - CiKind kind = type.kind().stackKind(); - Local local = new Local(kind, index, graph); - local.inputs().set(0, graph.start()); - if (type.isResolved()) { - local.setDeclaredType(type); - } - storeLocal(javaIndex, local); - javaIndex += kind.sizeInSlots(); - index++; - } - this.locks = new ArrayList(); - } - - public void initializeFrom(FrameState other) { - assert locals.length == other.localsSize() : "expected: " + locals.length + ", actual: " + other.localsSize(); - assert stack.length >= other.stackSize() : "expected: <=" + stack.length + ", actual: " + other.stackSize(); - - this.stackIndex = other.stackSize(); - for (int i = 0; i < other.localsSize(); i++) { - locals[i] = other.localAt(i); - } - for (int i = 0; i < other.stackSize(); i++) { - stack[i] = other.stackAt(i); - } - locks.clear(); - for (int i = 0; i < other.locksSize(); i++) { - locks.add(other.lockAt(i)); - } - } - - public FrameState create(int bci) { - return new FrameState(method, bci, locals, stack, stackIndex, locks, graph); - } - - @Override - public FrameState duplicateWithEmptyStack(int bci) { - FrameState frameState = new FrameState(method, bci, locals, new Value[0], 0, locks, graph); - frameState.setOuterFrameState(outerFrameState()); - return frameState; - } - - /** - * Pushes an instruction onto the stack with the expected type. - * @param kind the type expected for this instruction - * @param x the instruction to push onto the stack - */ - public void push(CiKind kind, Value x) { - assert kind != CiKind.Void; - xpush(assertKind(kind, x)); - if (kind.sizeInSlots() == 2) { - xpush(null); - } - } - - /** - * Pushes a value onto the stack without checking the type. - * @param x the instruction to push onto the stack - */ - public void xpush(Value x) { - assert x == null || !x.isDeleted(); - stack[stackIndex++] = x; - } - - /** - * Pushes a value onto the stack and checks that it is an int. - * @param x the instruction to push onto the stack - */ - public void ipush(Value x) { - xpush(assertInt(x)); - } - - /** - * Pushes a value onto the stack and checks that it is a float. - * @param x the instruction to push onto the stack - */ - public void fpush(Value x) { - xpush(assertFloat(x)); - } - - /** - * Pushes a value onto the stack and checks that it is an object. - * @param x the instruction to push onto the stack - */ - public void apush(Value x) { - xpush(assertObject(x)); - } - - /** - * Pushes a value onto the stack and checks that it is a word. - * @param x the instruction to push onto the stack - */ - public void wpush(Value x) { - xpush(assertWord(x)); - } - - /** - * Pushes a value onto the stack and checks that it is a JSR return address. - * @param x the instruction to push onto the stack - */ - public void jpush(Value x) { - xpush(assertJsr(x)); - } - - /** - * Pushes a value onto the stack and checks that it is a long. - * - * @param x the instruction to push onto the stack - */ - public void lpush(Value x) { - xpush(assertLong(x)); - xpush(null); - } - - /** - * Pushes a value onto the stack and checks that it is a double. - * @param x the instruction to push onto the stack - */ - public void dpush(Value x) { - xpush(assertDouble(x)); - xpush(null); - } - - public void pushReturn(CiKind kind, Value x) { - if (kind != CiKind.Void) { - push(kind.stackKind(), x); - } - } - - /** - * Pops an instruction off the stack with the expected type. - * @param kind the expected type - * @return the instruction on the top of the stack - */ - public Value pop(CiKind kind) { - assert kind != CiKind.Void; - if (kind.sizeInSlots() == 2) { - xpop(); - } - return assertKind(kind, xpop()); - } - - /** - * Pops a value off of the stack without checking the type. - * @return x the instruction popped off the stack - */ - public Value xpop() { - Value result = stack[--stackIndex]; - assert result == null || !result.isDeleted(); - return result; - } - - /** - * Pops a value off of the stack and checks that it is an int. - * @return x the instruction popped off the stack - */ - public Value ipop() { - return assertInt(xpop()); - } - - /** - * Pops a value off of the stack and checks that it is a float. - * @return x the instruction popped off the stack - */ - public Value fpop() { - return assertFloat(xpop()); - } - - /** - * Pops a value off of the stack and checks that it is an object. - * @return x the instruction popped off the stack - */ - public Value apop() { - return assertObject(xpop()); - } - - /** - * Pops a value off of the stack and checks that it is a word. - * @return x the instruction popped off the stack - */ - public Value wpop() { - return assertWord(xpop()); - } - - /** - * Pops a value off of the stack and checks that it is a JSR return address. - * @return x the instruction popped off the stack - */ - public Value jpop() { - return assertJsr(xpop()); - } - - /** - * Pops a value off of the stack and checks that it is a long. - * @return x the instruction popped off the stack - */ - public Value lpop() { - assertHigh(xpop()); - return assertLong(xpop()); - } - - /** - * Pops a value off of the stack and checks that it is a double. - * @return x the instruction popped off the stack - */ - public Value dpop() { - assertHigh(xpop()); - return assertDouble(xpop()); - } - - /** - * Pop the specified number of slots off of this stack and return them as an array of instructions. - * @param size the number of arguments off of the stack - * @return an array containing the arguments off of the stack - */ - public Value[] popArguments(int size) { - int base = stackIndex - size; - Value[] r = new Value[size]; - for (int i = 0; i < size; ++i) { - assert stack[base + i] != null || stack[base + i - 1].kind.jvmSlots == 2; - r[i] = stack[base + i]; - } - stackIndex = base; - return r; - } - - public CiKind peekKind() { - Value top = stackAt(stackSize() - 1); - if (top == null) { - top = stackAt(stackSize() - 2); - assert top != null; - assert top.kind.isDoubleWord(); - } - return top.kind; - } - - /** - * Truncates this stack to the specified size. - * @param size the size to truncate to - */ - public void truncateStack(int size) { - stackIndex = size; - assert stackIndex >= 0; - } - - /** - * Clears all values on this stack. - */ - public void clearStack() { - stackIndex = 0; - } - - /** - * Loads the local variable at the specified index. - * - * @param i the index of the local variable to load - * @return the instruction that produced the specified local - */ - public Value loadLocal(int i) { - Value x = locals[i]; - if (x != null) { - if (x instanceof Phi && ((Phi) x).isDead()) { - return null; - } - assert x.kind.isSingleWord() || locals[i + 1] == null || locals[i + 1] instanceof Phi; - } - return x; - } - - /** - * Stores a given local variable at the specified index. If the value is a {@linkplain CiKind#isDoubleWord() double word}, - * then the next local variable index is also overwritten. - * - * @param i the index at which to store - * @param x the instruction which produces the value for the local - */ - public void storeLocal(int i, Value x) { - locals[i] = x; - if (isDoubleWord(x)) { - // (tw) if this was a double word then kill i+1 - locals[i + 1] = null; - } - if (i > 0) { - // if there was a double word at i - 1, then kill it - Value p = locals[i - 1]; - if (isDoubleWord(p)) { - locals[i - 1] = null; - } - } - } - - /** - * Locks a new object within the specified IRScope. - * @param scope the IRScope in which this locking operation occurs - * @param obj the object being locked - */ - public void lock(Value obj) { - locks.add(obj); - } - - /** - * Unlock the lock on the top of the stack. - */ - public void unlock() { - locks.remove(locks.size() - 1); - } - - /** - * Get the value on the stack at the specified stack index. - * - * @param i the index into the stack, with {@code 0} being the bottom of the stack - * @return the instruction at the specified position in the stack - */ - public final Value stackAt(int i) { - return stack[i]; - } - - /** - * Gets the value in the local variables at the specified index. - * - * @param i the index into the locals - * @return the instruction that produced the value for the specified local - */ - public final Value localAt(int i) { - return locals[i]; - } - - /** - * Retrieves the lock at the specified index in the lock stack. - * @param i the index into the lock stack - * @return the instruction which produced the object at the specified location in the lock stack - */ - public final Value lockAt(int i) { - return locks.get(i); - } - - /** - * Returns the size of the local variables. - * - * @return the size of the local variables - */ - public int localsSize() { - return locals.length; - } - - /** - * Gets number of locks held by this frame state. - */ - public int locksSize() { - return locks.size(); - } - - /** - * Gets the current size (height) of the stack. - */ - public int stackSize() { - return stackIndex; - } - - public Iterator locals() { - return new ValueArrayIterator(locals); - } - - public Iterator stack() { - return new ValueArrayIterator(locals); - } - - public List locks() { - return Collections.unmodifiableList(locks); - } - - - private static class ValueArrayIterator implements Iterator { - private final Value[] array; - private int index; - private int length; - - public ValueArrayIterator(Value[] array, int length) { - assert length <= array.length; - this.array = array; - this.index = 0; - } - - public ValueArrayIterator(Value[] array) { - this(array, array.length); - } - - @Override - public boolean hasNext() { - return index < array.length; - } - - @Override - public Value next() { - return array[index++]; - } - - @Override - public void remove() { - throw new UnsupportedOperationException("cannot remove from array"); - } - - } - - - @Override - public FrameState duplicate(int bci) { - return create(bci); - } - - @Override - public Value valueAt(int i) { - if (i < locals.length) { - return locals[i]; - } else if (i < locals.length + stackIndex) { - return stack[i - locals.length]; - } else { - return locks.get(i - locals.length - stack.length); - } - } - - @Override - public void setValueAt(int i, Value v) { - if (i < locals.length) { - locals[i] = v; - } else if (i < locals.length + stackIndex) { - stack[i - locals.length] = v; - } else { - locks.set(i - locals.length - stack.length, v); - } - } - - @Override - public FrameState outerFrameState() { - return null; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/value/ValueUtil.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/value/ValueUtil.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,84 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.c1x.value; - -import com.sun.c1x.ir.*; -import com.sun.c1x.util.*; -import com.sun.cri.ci.*; - - -public class ValueUtil { - - public static Value assertKind(CiKind kind, Value x) { - assert x != null && (x.kind == kind) : "kind=" + kind + ", value=" + x + ((x == null) ? "" : ", value.kind=" + x.kind); - return x; - } - - public static Value assertLong(Value x) { - assert x != null && (x.kind == CiKind.Long); - return x; - } - - public static Value assertJsr(Value x) { - assert x != null && (x.kind == CiKind.Jsr); - return x; - } - - public static Value assertInt(Value x) { - assert x != null && (x.kind == CiKind.Int); - return x; - } - - public static Value assertFloat(Value x) { - assert x != null && (x.kind == CiKind.Float); - return x; - } - - public static Value assertObject(Value x) { - assert x != null && (x.kind == CiKind.Object); - return x; - } - - public static Value assertWord(Value x) { - assert x != null && (x.kind == CiKind.Word); - return x; - } - - public static Value assertDouble(Value x) { - assert x != null && (x.kind == CiKind.Double); - return x; - } - - public static void assertHigh(Value x) { - assert x == null; - } - - public static boolean typeMismatch(Value x, Value y) { - return y == null || !Util.archKindsEqual(x, y); - } - - public static boolean isDoubleWord(Value x) { - return x != null && x.kind.isDoubleWord(); - } - -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.compiler/src/com/sun/c1x/value/package-info.java --- a/graal/com.oracle.max.graal.compiler/src/com/sun/c1x/value/package-info.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2010, 2010, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/** - * @author Ben Titzer - */ -package com.sun.c1x.value; diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.graph/src/com/oracle/graal/graph/EdgeType.java --- a/graal/com.oracle.max.graal.graph/src/com/oracle/graal/graph/EdgeType.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.graph; - - -public enum EdgeType { - INPUTS, - USAGES, - PREDECESSORS, - SUCCESSORS; -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.graph/src/com/oracle/graal/graph/Graph.java --- a/graal/com.oracle.max.graal.graph/src/com/oracle/graal/graph/Graph.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,142 +0,0 @@ -/* - * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.graph; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; - -public class Graph { - - private final ArrayList nodes; - private final StartNode start; - int nextId; - - static int nextGraphId = 0; - int id = nextGraphId++; - - @Override - public String toString() { - return "Graph " + id; - } - - public Graph() { - nodes = new ArrayList(); - start = new StartNode(this); - } - - public List getNodes() { - return Collections.unmodifiableList(nodes); - } - - int register(Node node) { - int id = nextId++; - nodes.add(id, node); - return id; - } - - void unregister(Node node) { - nodes.set(node.id(), Node.Null); - } - - public StartNode start() { - return start; - } - - public NodeBitMap createNodeBitMap() { - return new NodeBitMap(this); - } - - public NodeMap createNodeMap() { - return new NodeMap(this); - } - - public NodeWorklist createNodeWorklist() { - return new NodeWorklist(this); - } - - public Map addDuplicate(Collection nodes, Map replacements) { - Map newNodes = new HashMap(); - // create node duplicates - for (Node node : nodes) { - if (node != null && !replacements.containsKey(node)) { - Node newNode = node.copy(this); - assert newNode.getClass() == node.getClass(); - newNodes.put(node, newNode); - } - } - // re-wire inputs - for (Entry entry : newNodes.entrySet()) { - Node oldNode = entry.getKey(); - Node node = entry.getValue(); - for (int i = 0; i < oldNode.inputs().size(); i++) { - Node input = oldNode.inputs().get(i); - Node target = replacements.get(input); - if (target == null) { - target = newNodes.get(input); - } - node.inputs().set(i, target); - } - } - for (Entry entry : replacements.entrySet()) { - Node oldNode = entry.getKey(); - Node node = entry.getValue(); - for (int i = 0; i < oldNode.inputs().size(); i++) { - Node input = oldNode.inputs().get(i); - if (newNodes.containsKey(input)) { - node.inputs().set(i, newNodes.get(input)); - } - } - } - // re-wire successors - for (Entry entry : newNodes.entrySet()) { - Node oldNode = entry.getKey(); - Node node = entry.getValue(); - for (int i = 0; i < oldNode.predecessors().size(); i++) { - Node pred = oldNode.predecessors().get(i); - int predIndex = oldNode.predecessorsIndex().get(i); - Node source = replacements.get(pred); - if (source == null) { - source = newNodes.get(pred); - } - source.successors().set(predIndex, node); - } - } - for (Entry entry : replacements.entrySet()) { - Node oldNode = entry.getKey(); - Node node = entry.getValue(); - for (int i = 0; i < oldNode.predecessors().size(); i++) { - Node pred = oldNode.predecessors().get(i); - int predIndex = oldNode.predecessorsIndex().get(i); - if (newNodes.containsKey(pred)) { - newNodes.get(pred).successors().set(predIndex, node); - } - } - } - return newNodes; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.graph/src/com/oracle/graal/graph/Node.java --- a/graal/com.oracle.max.graal.graph/src/com/oracle/graal/graph/Node.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,180 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.graph; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -public abstract class Node { - - public static final Node Null = null; - public static final int DeletedID = -1; - - final Graph graph; - private int id; - final NodeArray inputs; - final NodeArray successors; - final ArrayList usages; - final ArrayList predecessors; - final ArrayList predecessorsIndex; - - public Node(int inputCount, int successorCount, Graph graph) { - assert graph != null; - this.graph = graph; - this.id = graph.register(this); - this.inputs = new NodeArray(this, inputCount); - this.successors = new NodeArray(this, successorCount); - this.predecessors = new ArrayList(); - this.usages = new ArrayList(); - this.predecessorsIndex = new ArrayList(); - } - - public List predecessors() { - return Collections.unmodifiableList(predecessors); - } - - public List predecessorsIndex() { - return Collections.unmodifiableList(predecessorsIndex); - } - - public List usages() { - return Collections.unmodifiableList(usages); - } - - public NodeArray inputs() { - return inputs; - } - - public NodeArray successors() { - return successors; - } - - public int id() { - return id; - } - - public Graph graph() { - return graph; - } - - public T lookup(Class clazz) { - return null; - } - - public String shortName() { - return getClass().getSimpleName(); - } - - public Node replace(Node other) { - assert !isDeleted() && (other == null || !other.isDeleted()); - assert other == null || other.graph == graph; - for (Node usage : usages) { - usage.inputs.replaceFirstOccurrence(this, other); - } - int z = 0; - for (Node predecessor : predecessors) { - int predIndex = predecessorsIndex.get(z); - predecessor.successors.nodes[predIndex] = other; - ++z; - } - if (other != null) { - other.usages.addAll(usages); - other.predecessors.addAll(predecessors); - other.predecessorsIndex.addAll(predecessorsIndex); - } - usages.clear(); - predecessors.clear(); - predecessorsIndex.clear(); - delete(); - return other; - } - - public boolean isDeleted() { - return id == DeletedID; - } - - public void delete() { - assert !isDeleted(); - assert usages.size() == 0 && predecessors.size() == 0 : "id: " + id + ", usages: " + usages.size() + ", predecessors: " + predecessors().size(); - assert predecessorsIndex.size() == 0; - for (int i = 0; i < inputs.size(); ++i) { - inputs.set(i, Null); - } - for (int i = 0; i < successors.size(); ++i) { - successors.set(i, Null); - } - assert predecessors().size() == 0 && usages().size() == 0; - // make sure its not connected. pred usages - graph.unregister(this); - id = DeletedID; - assert isDeleted(); - } - - public Node copy() { - return copy(graph); - } - - /** - * - * @param into - * @return - */ - public abstract Node copy(Graph into); - - /** - * - * @return - */ - protected int inputCount() { - return 0; - } - - /** - * - * @return - */ - protected int successorCount() { - return 0; - } - - /** - * Provides a {@link Map} of properties of this node for use in debugging (e.g., to view in the ideal graph - * visualizer). Subclasses overriding this method should add to the map returned by their superclass. - */ - public Map getDebugProperties() { - Map map = new HashMap(); - map.put("inputCount", inputCount()); - map.put("usageCount", usages.size()); - map.put("successorCount", successorCount()); - map.put("predecessorCount", predecessors.size()); - return map; - } - - @Override - public String toString() { - return this.getClass().getSimpleName() + "-" + this.id(); - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.graph/src/com/oracle/graal/graph/NodeArray.java --- a/graal/com.oracle.max.graal.graph/src/com/oracle/graal/graph/NodeArray.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,150 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.graph; - -import java.util.AbstractList; -import java.util.Arrays; -import java.util.Iterator; - -public class NodeArray extends AbstractList { - - private final Node node; - final Node[] nodes; - - public NodeArray(Node node, int length) { - this.node = node; - this.nodes = new Node[length]; - } - - @Override - public Iterator iterator() { - return Arrays.asList(this.nodes).iterator(); - } - - private Node self() { - return this.node; - } - - @Override - public Node set(int index, Node node) { - assert node == Node.Null || node.graph == self().graph : "node is from different graph: (this=" + this + ") and (node=" + node + ")"; - assert node == Node.Null || node.id() != Node.DeletedID : "inserted node must not be deleted"; - Node old = nodes[index]; - - if (old != node) { - nodes[index] = node; - if (self().inputs == this) { - if (old != null) { - old.usages.remove(self()); - } - if (node != null) { - node.usages.add(self()); - } - } else { - assert self().successors == this; - if (old != null) { - for (int i = 0; i < old.predecessors.size(); ++i) { - Node cur = old.predecessors.get(i); - if (cur == self() && old.predecessorsIndex.get(i) == index) { - old.predecessors.remove(i); - old.predecessorsIndex.remove(i); - } - } - } - if (node != null) { - node.predecessors.add(self()); - node.predecessorsIndex.add(index); - } - } - } - - return old; - } - - public void setAll(NodeArray other) { - assert size() == other.size(); - for (int i = 0; i < other.size(); i++) { - set(i, other.get(i)); - } - } - - @Override - public Node get(int index) { - return nodes[index]; - } - - @Override - public Node[] toArray() { - return Arrays.copyOf(nodes, nodes.length); - } - - boolean replaceFirstOccurrence(Node toReplace, Node replacement) { - for (int i = 0; i < nodes.length; i++) { - if (nodes[i] == toReplace) { - nodes[i] = replacement; - return true; - } - } - return false; - } - - public int replace(Node toReplace, Node replacement) { - int result = 0; - for (int i = 0; i < nodes.length; i++) { - if (nodes[i] == toReplace) { - set(i, replacement); - result++; - } - } - return result; - } - - public void setAndClear(int index, Node clearedNode, int clearedIndex) { - assert self().successors == this; - Node value = clearedNode.successors.get(clearedIndex); - assert value != Node.Null; - clearedNode.successors.nodes[clearedIndex] = Node.Null; - set(index, Node.Null); - nodes[index] = value; - - for (int i = 0; i < value.predecessors.size(); ++i) { - if (value.predecessors.get(i) == clearedNode && value.predecessorsIndex.get(i) == clearedIndex) { - value.predecessors.set(i, self()); - value.predecessorsIndex.set(i, index); - return; - } - } - assert false; - } - - @Override - public int size() { - return nodes.length; - } - - public void clearAll() { - for (int i = 0; i < nodes.length; i++) { - set(i, Node.Null); - } - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.graph/src/com/oracle/graal/graph/NodeBitMap.java --- a/graal/com.oracle.max.graal.graph/src/com/oracle/graal/graph/NodeBitMap.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,78 +0,0 @@ -/* - * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.graph; - -import com.sun.cri.ci.CiBitMap; - - -public final class NodeBitMap { - - private final CiBitMap bitMap; - private final Graph graph; - - NodeBitMap(Graph graph) { - this.graph = graph; - bitMap = new CiBitMap(graph.nextId); - } - - public Graph graph() { - return graph; - } - - public boolean setIntersect(NodeBitMap other) { - return bitMap.setIntersect(other.bitMap); - } - - public void setUnion(NodeBitMap other) { - bitMap.setUnion(other.bitMap); - } - - public boolean isMarked(Node node) { - check(node); - return bitMap.get(node.id()); - } - - public boolean isNew(Node node) { - return node.id() >= bitMap.size(); - } - - public void mark(Node node) { - check(node); - bitMap.set(node.id()); - } - - public void clear(Node node) { - check(node); - bitMap.clear(node.id()); - } - - private void check(Node node) { - assert node.graph == graph : "this node is not part of the graph"; - assert !isNew(node) : "this node (" + node.id() + ") was added to the graph after creating the node bitmap (" + bitMap.length() + ")"; - } - - @Override - public String toString() { - return bitMap.toBinaryString(-1); - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.graph/src/com/oracle/graal/graph/NodeIterator.java --- a/graal/com.oracle.max.graal.graph/src/com/oracle/graal/graph/NodeIterator.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,78 +0,0 @@ -/* - * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.graph; - -import java.util.LinkedList; -import java.util.List; - - -public class NodeIterator { - public static NodeBitMap iterate(EdgeType e, Node start, NodeBitMap constraint, NodeVisitor visitor) { - LinkedList nodes = new LinkedList(); - NodeBitMap nodeBitMap = start.graph.createNodeBitMap(); - - add(nodes, nodeBitMap, start, constraint, null); - while (nodes.size() > 0) { - Node n = nodes.remove(); - if (visitor != null) { - boolean followEdges = visitor.visit(n); - if (!followEdges) { - continue; - } - } - switch(e) { - case INPUTS: - for (Node inputs : n.inputs()) { - add(nodes, nodeBitMap, inputs, constraint, n.usages()); - } - break; - case USAGES: - for (Node usage : n.usages()) { - add(nodes, nodeBitMap, usage, constraint, n.inputs()); - } - break; - case PREDECESSORS: - for (Node preds : n.predecessors()) { - add(nodes, nodeBitMap, preds, constraint, n.successors()); - } - break; - case SUCCESSORS: - for (Node succ : n.successors()) { - add(nodes, nodeBitMap, succ, constraint, n.predecessors()); - } - break; - default: - assert false : "unknown edge type"; - } - } - - return nodeBitMap; - } - - private static void add(List nodes, NodeBitMap nodeBitMap, Node node, NodeBitMap constraint, List others) { - if (node != null && !nodeBitMap.isMarked(node) && (constraint == null || constraint.isMarked(node))) { - nodes.add(node); - nodeBitMap.mark(node); - } - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.graph/src/com/oracle/graal/graph/NodeMap.java --- a/graal/com.oracle.max.graal.graph/src/com/oracle/graal/graph/NodeMap.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.graph; - - - -public final class NodeMap { - - private final Object[] values; - private final Graph graph; - - NodeMap(Graph graph) { - this.graph = graph; - values = new Object[graph.nextId]; - } - - @SuppressWarnings("unchecked") - public T get(Node node) { - check(node); - return (T) values[node.id()]; - } - - public void set(Node node, T value) { - check(node); - values[node.id()] = value; - } - - public int size() { - return values.length; - } - - private void check(Node node) { - assert node.graph == graph : "this node is not part of the graph"; - assert node.id() < values.length : "this node was added to the graph after creating the node map"; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.graph/src/com/oracle/graal/graph/NodeVisitor.java --- a/graal/com.oracle.max.graal.graph/src/com/oracle/graal/graph/NodeVisitor.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.graph; - - -public interface NodeVisitor { - boolean visit(Node n); -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.graph/src/com/oracle/graal/graph/NodeWorklist.java --- a/graal/com.oracle.max.graal.graph/src/com/oracle/graal/graph/NodeWorklist.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,128 +0,0 @@ -/* - * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.graph; - -import java.util.ArrayDeque; -import java.util.Iterator; -import java.util.Queue; - - -public class NodeWorklist implements Iterable { - private final NodeBitMap visited; - private final Queue worklist; - - NodeWorklist(Graph graph) { - visited = graph.createNodeBitMap(); - worklist = new ArrayDeque(); - } - - public void add(Node node) { - if (node != null && !visited.isMarked(node)) { - visited.mark(node); - worklist.add(node); - } - } - - public boolean isMarked(Node node) { - return visited.isMarked(node); - } - - private static class QueueConsumingIterator implements Iterator { - private final Queue queue; - - public QueueConsumingIterator(Queue queue) { - this.queue = queue; - } - - @Override - public boolean hasNext() { - return !queue.isEmpty(); - } - - @Override - public Node next() { - return queue.remove(); - } - - @Override - public void remove() { - throw new UnsupportedOperationException(); - } - } - - @Override - public Iterator iterator() { - return new QueueConsumingIterator(worklist); - } - - private static class UnmarkedNodeIterator implements Iterator { - private final NodeBitMap visited; - private Iterator nodes; - private Node nextNode; - - public UnmarkedNodeIterator(NodeBitMap visited, Iterator nodes) { - this.visited = visited; - this.nodes = nodes; - forward(); - } - - private void forward() { - do { - if (!nodes.hasNext()) { - nextNode = null; - return; - } - nextNode = nodes.next(); - } while (visited.isMarked(nextNode)); - } - - @Override - public boolean hasNext() { - return nextNode != null; - } - - @Override - public Node next() { - try { - return nextNode; - } finally { - forward(); - } - } - - @Override - public void remove() { - throw new UnsupportedOperationException(); - } - - } - - public Iterable unmarkedNodes() { - return new Iterable() { - @Override - public Iterator iterator() { - return new UnmarkedNodeIterator(visited, visited.graph().getNodes().iterator()); - } - }; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.graph/src/com/oracle/graal/graph/Op.java --- a/graal/com.oracle.max.graal.graph/src/com/oracle/graal/graph/Op.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.graph; - - -public interface Op { - -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.graph/src/com/oracle/graal/graph/Phase.java --- a/graal/com.oracle.max.graal.graph/src/com/oracle/graal/graph/Phase.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.graph; - -public abstract class Phase { - - public final void apply(Graph graph) { - assert graph != null; - run(graph); - } - - protected abstract void run(Graph graph); -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.graph/src/com/oracle/graal/graph/StartNode.java --- a/graal/com.oracle.max.graal.graph/src/com/oracle/graal/graph/StartNode.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.graph; - -public class StartNode extends Node { - - private static final int INPUT_COUNT = 0; - - private static final int SUCCESSOR_COUNT = 1; - private static final int SUCCESSOR_START = 0; - - @Override - protected int inputCount() { - return super.inputCount() + INPUT_COUNT; - } - - @Override - protected int successorCount() { - return super.successorCount() + SUCCESSOR_COUNT; - } - - public Node start() { - return successors().get(super.successorCount() + SUCCESSOR_START); - } - - public Node setStart(Node next) { - return successors().set(super.successorCount() + SUCCESSOR_START, next); - } - - StartNode(Graph graph) { - super(INPUT_COUNT, SUCCESSOR_COUNT, graph); - } - - @Override - public Node replace(Node other) { - throw new UnsupportedOperationException(); - } - - @Override - public void delete() { - throw new UnsupportedOperationException(); - } - - @Override - public Node copy(Graph into) { - throw new UnsupportedOperationException(); - } - -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.graph/src/com/oracle/graal/graph/package-info.java --- a/graal/com.oracle.max.graal.graph/src/com/oracle/graal/graph/package-info.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -/** - * This package contains the Node base class and the Graph container class of the Graal IR. - * - * @author Gilles Duboscq - * @author Lukas Stadler - * @author Thomas Wuerthinger - */ -package com.oracle.graal.graph; diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.graph/src/com/oracle/max/graal/graph/EdgeType.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.graph/src/com/oracle/max/graal/graph/EdgeType.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.graph; + + +public enum EdgeType { + INPUTS, + USAGES, + PREDECESSORS, + SUCCESSORS; +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.graph/src/com/oracle/max/graal/graph/Graph.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.graph/src/com/oracle/max/graal/graph/Graph.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.graph; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +public class Graph { + + private final ArrayList nodes; + private final StartNode start; + int nextId; + + static int nextGraphId = 0; + int id = nextGraphId++; + + @Override + public String toString() { + return "Graph " + id; + } + + public Graph() { + nodes = new ArrayList(); + start = new StartNode(this); + } + + public List getNodes() { + return Collections.unmodifiableList(nodes); + } + + int register(Node node) { + int id = nextId++; + nodes.add(id, node); + return id; + } + + void unregister(Node node) { + nodes.set(node.id(), Node.Null); + } + + public StartNode start() { + return start; + } + + public NodeBitMap createNodeBitMap() { + return new NodeBitMap(this); + } + + public NodeMap createNodeMap() { + return new NodeMap(this); + } + + public NodeWorklist createNodeWorklist() { + return new NodeWorklist(this); + } + + public Map addDuplicate(Collection nodes, Map replacements) { + Map newNodes = new HashMap(); + // create node duplicates + for (Node node : nodes) { + if (node != null && !replacements.containsKey(node)) { + Node newNode = node.copy(this); + assert newNode.getClass() == node.getClass(); + newNodes.put(node, newNode); + } + } + // re-wire inputs + for (Entry entry : newNodes.entrySet()) { + Node oldNode = entry.getKey(); + Node node = entry.getValue(); + for (int i = 0; i < oldNode.inputs().size(); i++) { + Node input = oldNode.inputs().get(i); + Node target = replacements.get(input); + if (target == null) { + target = newNodes.get(input); + } + node.inputs().set(i, target); + } + } + for (Entry entry : replacements.entrySet()) { + Node oldNode = entry.getKey(); + Node node = entry.getValue(); + for (int i = 0; i < oldNode.inputs().size(); i++) { + Node input = oldNode.inputs().get(i); + if (newNodes.containsKey(input)) { + node.inputs().set(i, newNodes.get(input)); + } + } + } + // re-wire successors + for (Entry entry : newNodes.entrySet()) { + Node oldNode = entry.getKey(); + Node node = entry.getValue(); + for (int i = 0; i < oldNode.predecessors().size(); i++) { + Node pred = oldNode.predecessors().get(i); + int predIndex = oldNode.predecessorsIndex().get(i); + Node source = replacements.get(pred); + if (source == null) { + source = newNodes.get(pred); + } + source.successors().set(predIndex, node); + } + } + for (Entry entry : replacements.entrySet()) { + Node oldNode = entry.getKey(); + Node node = entry.getValue(); + for (int i = 0; i < oldNode.predecessors().size(); i++) { + Node pred = oldNode.predecessors().get(i); + int predIndex = oldNode.predecessorsIndex().get(i); + if (newNodes.containsKey(pred)) { + newNodes.get(pred).successors().set(predIndex, node); + } + } + } + return newNodes; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.graph/src/com/oracle/max/graal/graph/Node.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.graph/src/com/oracle/max/graal/graph/Node.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.graph; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public abstract class Node { + + public static final Node Null = null; + public static final int DeletedID = -1; + + final Graph graph; + private int id; + final NodeArray inputs; + final NodeArray successors; + final ArrayList usages; + final ArrayList predecessors; + final ArrayList predecessorsIndex; + + public Node(int inputCount, int successorCount, Graph graph) { + assert graph != null; + this.graph = graph; + this.id = graph.register(this); + this.inputs = new NodeArray(this, inputCount); + this.successors = new NodeArray(this, successorCount); + this.predecessors = new ArrayList(); + this.usages = new ArrayList(); + this.predecessorsIndex = new ArrayList(); + } + + public List predecessors() { + return Collections.unmodifiableList(predecessors); + } + + public List predecessorsIndex() { + return Collections.unmodifiableList(predecessorsIndex); + } + + public List usages() { + return Collections.unmodifiableList(usages); + } + + public NodeArray inputs() { + return inputs; + } + + public NodeArray successors() { + return successors; + } + + public int id() { + return id; + } + + public Graph graph() { + return graph; + } + + public T lookup(Class clazz) { + return null; + } + + public String shortName() { + return getClass().getSimpleName(); + } + + public Node replace(Node other) { + assert !isDeleted() && (other == null || !other.isDeleted()); + assert other == null || other.graph == graph; + for (Node usage : usages) { + usage.inputs.replaceFirstOccurrence(this, other); + } + int z = 0; + for (Node predecessor : predecessors) { + int predIndex = predecessorsIndex.get(z); + predecessor.successors.nodes[predIndex] = other; + ++z; + } + if (other != null) { + other.usages.addAll(usages); + other.predecessors.addAll(predecessors); + other.predecessorsIndex.addAll(predecessorsIndex); + } + usages.clear(); + predecessors.clear(); + predecessorsIndex.clear(); + delete(); + return other; + } + + public boolean isDeleted() { + return id == DeletedID; + } + + public void delete() { + assert !isDeleted(); + assert usages.size() == 0 && predecessors.size() == 0 : "id: " + id + ", usages: " + usages.size() + ", predecessors: " + predecessors().size(); + assert predecessorsIndex.size() == 0; + for (int i = 0; i < inputs.size(); ++i) { + inputs.set(i, Null); + } + for (int i = 0; i < successors.size(); ++i) { + successors.set(i, Null); + } + assert predecessors().size() == 0 && usages().size() == 0; + // make sure its not connected. pred usages + graph.unregister(this); + id = DeletedID; + assert isDeleted(); + } + + public Node copy() { + return copy(graph); + } + + /** + * + * @param into + * @return + */ + public abstract Node copy(Graph into); + + /** + * + * @return + */ + protected int inputCount() { + return 0; + } + + /** + * + * @return + */ + protected int successorCount() { + return 0; + } + + /** + * Provides a {@link Map} of properties of this node for use in debugging (e.g., to view in the ideal graph + * visualizer). Subclasses overriding this method should add to the map returned by their superclass. + */ + public Map getDebugProperties() { + Map map = new HashMap(); + map.put("inputCount", inputCount()); + map.put("usageCount", usages.size()); + map.put("successorCount", successorCount()); + map.put("predecessorCount", predecessors.size()); + return map; + } + + @Override + public String toString() { + return this.getClass().getSimpleName() + "-" + this.id(); + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.graph/src/com/oracle/max/graal/graph/NodeArray.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.graph/src/com/oracle/max/graal/graph/NodeArray.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.graph; + +import java.util.AbstractList; +import java.util.Arrays; +import java.util.Iterator; + +public class NodeArray extends AbstractList { + + private final Node node; + final Node[] nodes; + + public NodeArray(Node node, int length) { + this.node = node; + this.nodes = new Node[length]; + } + + @Override + public Iterator iterator() { + return Arrays.asList(this.nodes).iterator(); + } + + private Node self() { + return this.node; + } + + @Override + public Node set(int index, Node node) { + assert node == Node.Null || node.graph == self().graph : "node is from different graph: (this=" + this + ") and (node=" + node + ")"; + assert node == Node.Null || node.id() != Node.DeletedID : "inserted node must not be deleted"; + Node old = nodes[index]; + + if (old != node) { + nodes[index] = node; + if (self().inputs == this) { + if (old != null) { + old.usages.remove(self()); + } + if (node != null) { + node.usages.add(self()); + } + } else { + assert self().successors == this; + if (old != null) { + for (int i = 0; i < old.predecessors.size(); ++i) { + Node cur = old.predecessors.get(i); + if (cur == self() && old.predecessorsIndex.get(i) == index) { + old.predecessors.remove(i); + old.predecessorsIndex.remove(i); + } + } + } + if (node != null) { + node.predecessors.add(self()); + node.predecessorsIndex.add(index); + } + } + } + + return old; + } + + public void setAll(NodeArray other) { + assert size() == other.size(); + for (int i = 0; i < other.size(); i++) { + set(i, other.get(i)); + } + } + + @Override + public Node get(int index) { + return nodes[index]; + } + + @Override + public Node[] toArray() { + return Arrays.copyOf(nodes, nodes.length); + } + + boolean replaceFirstOccurrence(Node toReplace, Node replacement) { + for (int i = 0; i < nodes.length; i++) { + if (nodes[i] == toReplace) { + nodes[i] = replacement; + return true; + } + } + return false; + } + + public int replace(Node toReplace, Node replacement) { + int result = 0; + for (int i = 0; i < nodes.length; i++) { + if (nodes[i] == toReplace) { + set(i, replacement); + result++; + } + } + return result; + } + + public void setAndClear(int index, Node clearedNode, int clearedIndex) { + assert self().successors == this; + Node value = clearedNode.successors.get(clearedIndex); + assert value != Node.Null; + clearedNode.successors.nodes[clearedIndex] = Node.Null; + set(index, Node.Null); + nodes[index] = value; + + for (int i = 0; i < value.predecessors.size(); ++i) { + if (value.predecessors.get(i) == clearedNode && value.predecessorsIndex.get(i) == clearedIndex) { + value.predecessors.set(i, self()); + value.predecessorsIndex.set(i, index); + return; + } + } + assert false; + } + + @Override + public int size() { + return nodes.length; + } + + public void clearAll() { + for (int i = 0; i < nodes.length; i++) { + set(i, Node.Null); + } + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.graph/src/com/oracle/max/graal/graph/NodeBitMap.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.graph/src/com/oracle/max/graal/graph/NodeBitMap.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.graph; + +import com.sun.cri.ci.CiBitMap; + + +public final class NodeBitMap { + + private final CiBitMap bitMap; + private final Graph graph; + + NodeBitMap(Graph graph) { + this.graph = graph; + bitMap = new CiBitMap(graph.nextId); + } + + public Graph graph() { + return graph; + } + + public boolean setIntersect(NodeBitMap other) { + return bitMap.setIntersect(other.bitMap); + } + + public void setUnion(NodeBitMap other) { + bitMap.setUnion(other.bitMap); + } + + public boolean isMarked(Node node) { + check(node); + return bitMap.get(node.id()); + } + + public boolean isNew(Node node) { + return node.id() >= bitMap.size(); + } + + public void mark(Node node) { + check(node); + bitMap.set(node.id()); + } + + public void clear(Node node) { + check(node); + bitMap.clear(node.id()); + } + + private void check(Node node) { + assert node.graph == graph : "this node is not part of the graph"; + assert !isNew(node) : "this node (" + node.id() + ") was added to the graph after creating the node bitmap (" + bitMap.length() + ")"; + } + + @Override + public String toString() { + return bitMap.toBinaryString(-1); + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.graph/src/com/oracle/max/graal/graph/NodeIterator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.graph/src/com/oracle/max/graal/graph/NodeIterator.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.graph; + +import java.util.LinkedList; +import java.util.List; + + +public class NodeIterator { + public static NodeBitMap iterate(EdgeType e, Node start, NodeBitMap constraint, NodeVisitor visitor) { + LinkedList nodes = new LinkedList(); + NodeBitMap nodeBitMap = start.graph.createNodeBitMap(); + + add(nodes, nodeBitMap, start, constraint, null); + while (nodes.size() > 0) { + Node n = nodes.remove(); + if (visitor != null) { + boolean followEdges = visitor.visit(n); + if (!followEdges) { + continue; + } + } + switch(e) { + case INPUTS: + for (Node inputs : n.inputs()) { + add(nodes, nodeBitMap, inputs, constraint, n.usages()); + } + break; + case USAGES: + for (Node usage : n.usages()) { + add(nodes, nodeBitMap, usage, constraint, n.inputs()); + } + break; + case PREDECESSORS: + for (Node preds : n.predecessors()) { + add(nodes, nodeBitMap, preds, constraint, n.successors()); + } + break; + case SUCCESSORS: + for (Node succ : n.successors()) { + add(nodes, nodeBitMap, succ, constraint, n.predecessors()); + } + break; + default: + assert false : "unknown edge type"; + } + } + + return nodeBitMap; + } + + private static void add(List nodes, NodeBitMap nodeBitMap, Node node, NodeBitMap constraint, List others) { + if (node != null && !nodeBitMap.isMarked(node) && (constraint == null || constraint.isMarked(node))) { + nodes.add(node); + nodeBitMap.mark(node); + } + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.graph/src/com/oracle/max/graal/graph/NodeMap.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.graph/src/com/oracle/max/graal/graph/NodeMap.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.graph; + + + +public final class NodeMap { + + private final Object[] values; + private final Graph graph; + + NodeMap(Graph graph) { + this.graph = graph; + values = new Object[graph.nextId]; + } + + @SuppressWarnings("unchecked") + public T get(Node node) { + check(node); + return (T) values[node.id()]; + } + + public void set(Node node, T value) { + check(node); + values[node.id()] = value; + } + + public int size() { + return values.length; + } + + private void check(Node node) { + assert node.graph == graph : "this node is not part of the graph"; + assert node.id() < values.length : "this node was added to the graph after creating the node map"; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.graph/src/com/oracle/max/graal/graph/NodeVisitor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.graph/src/com/oracle/max/graal/graph/NodeVisitor.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.graph; + + +public interface NodeVisitor { + boolean visit(Node n); +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.graph/src/com/oracle/max/graal/graph/NodeWorklist.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.graph/src/com/oracle/max/graal/graph/NodeWorklist.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.graph; + +import java.util.ArrayDeque; +import java.util.Iterator; +import java.util.Queue; + + +public class NodeWorklist implements Iterable { + private final NodeBitMap visited; + private final Queue worklist; + + NodeWorklist(Graph graph) { + visited = graph.createNodeBitMap(); + worklist = new ArrayDeque(); + } + + public void add(Node node) { + if (node != null && !visited.isMarked(node)) { + visited.mark(node); + worklist.add(node); + } + } + + public boolean isMarked(Node node) { + return visited.isMarked(node); + } + + private static class QueueConsumingIterator implements Iterator { + private final Queue queue; + + public QueueConsumingIterator(Queue queue) { + this.queue = queue; + } + + @Override + public boolean hasNext() { + return !queue.isEmpty(); + } + + @Override + public Node next() { + return queue.remove(); + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + } + + @Override + public Iterator iterator() { + return new QueueConsumingIterator(worklist); + } + + private static class UnmarkedNodeIterator implements Iterator { + private final NodeBitMap visited; + private Iterator nodes; + private Node nextNode; + + public UnmarkedNodeIterator(NodeBitMap visited, Iterator nodes) { + this.visited = visited; + this.nodes = nodes; + forward(); + } + + private void forward() { + do { + if (!nodes.hasNext()) { + nextNode = null; + return; + } + nextNode = nodes.next(); + } while (visited.isMarked(nextNode)); + } + + @Override + public boolean hasNext() { + return nextNode != null; + } + + @Override + public Node next() { + try { + return nextNode; + } finally { + forward(); + } + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + + } + + public Iterable unmarkedNodes() { + return new Iterable() { + @Override + public Iterator iterator() { + return new UnmarkedNodeIterator(visited, visited.graph().getNodes().iterator()); + } + }; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.graph/src/com/oracle/max/graal/graph/Op.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.graph/src/com/oracle/max/graal/graph/Op.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.graph; + + +public interface Op { + +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.graph/src/com/oracle/max/graal/graph/Phase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.graph/src/com/oracle/max/graal/graph/Phase.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.graph; + +public abstract class Phase { + + public final void apply(Graph graph) { + assert graph != null; + run(graph); + } + + protected abstract void run(Graph graph); +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.graph/src/com/oracle/max/graal/graph/StartNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.graph/src/com/oracle/max/graal/graph/StartNode.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.graph; + +public class StartNode extends Node { + + private static final int INPUT_COUNT = 0; + + private static final int SUCCESSOR_COUNT = 1; + private static final int SUCCESSOR_START = 0; + + @Override + protected int inputCount() { + return super.inputCount() + INPUT_COUNT; + } + + @Override + protected int successorCount() { + return super.successorCount() + SUCCESSOR_COUNT; + } + + public Node start() { + return successors().get(super.successorCount() + SUCCESSOR_START); + } + + public Node setStart(Node next) { + return successors().set(super.successorCount() + SUCCESSOR_START, next); + } + + StartNode(Graph graph) { + super(INPUT_COUNT, SUCCESSOR_COUNT, graph); + } + + @Override + public Node replace(Node other) { + throw new UnsupportedOperationException(); + } + + @Override + public void delete() { + throw new UnsupportedOperationException(); + } + + @Override + public Node copy(Graph into) { + throw new UnsupportedOperationException(); + } + +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.graph/src/com/oracle/max/graal/graph/package-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.graph/src/com/oracle/max/graal/graph/package-info.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +/** + * This package contains the Node base class and the Graph container class of the Graal IR. + * + * @author Gilles Duboscq + * @author Lukas Stadler + * @author Thomas Wuerthinger + */ +package com.oracle.max.graal.graph; diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.graph/test/com/oracle/graal/graph/NodeTest.java --- a/graal/com.oracle.max.graal.graph/test/com/oracle/graal/graph/NodeTest.java Wed Jun 08 08:45:47 2011 +0200 +++ b/graal/com.oracle.max.graal.graph/test/com/oracle/graal/graph/NodeTest.java Wed Jun 08 08:59:54 2011 +0200 @@ -26,6 +26,9 @@ import org.junit.Test; +import com.oracle.max.graal.graph.Graph; +import com.oracle.max.graal.graph.Node; + public class NodeTest { @Test diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.graphviz/src/com/oracle/graal/graph/vis/GraphvizPrinter.java --- a/graal/com.oracle.max.graal.graphviz/src/com/oracle/graal/graph/vis/GraphvizPrinter.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,202 +0,0 @@ -/* - * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.graph.vis; - -import java.awt.Color; -import java.io.OutputStream; -import java.io.PrintStream; -import java.util.HashMap; -import java.util.HashSet; - -import com.oracle.graal.graph.Graph; -import com.oracle.graal.graph.Node; -import com.oracle.graal.graph.NodeArray; - -/** - * Generates a representation of {@link Node Nodes} or entire {@link Graph Graphs} in the DOT language that can be - * visualized with Graphviz. - */ -public class GraphvizPrinter { - - public static final Color NODE_BGCOLOR = Color.WHITE; - private static final String NODE_BGCOLOR_STRING = formatColorString(NODE_BGCOLOR); - - private static String formatColorString(Color c) { - return String.format("#%02x%02x%02x%02x", c.getRed(), c.getGreen(), c.getBlue(), c.getAlpha()); - } - - private final PrintStream out; - private final HashSet> omittedClasses = new HashSet>(); - private final HashMap, String> classColors = new HashMap, String>(); - - /** - * Creates a new {@link GraphvizPrinter} that writes to the specified output stream. - */ - public GraphvizPrinter(OutputStream out) { - this.out = new PrintStream(out); - } - - public void addOmittedClass(Class clazz) { - omittedClasses.add(clazz); - } - - public void addClassColor(Class clazz, String color) { - classColors.put(clazz, color); - } - - /** - * Opens a graph with the specified title (label). Call this before printing any nodes, but not more than once - * without calling {@link #end()} first. - * - * @param title - * The graph's label. - */ - public void begin(String title) { - out.println("digraph g {"); - if (title != null) { - out.println(" label=\"" + title + "\";"); - } - } - - /** - * Closes the graph. No nodes should be printed afterwards. Another graph can be opened with {@link #begin(String)}, - * but many Graphviz output plugins ignore additional graphs in their input. - */ - public void end() { - out.println("}"); - } - - /** - * Prints all nodes and edges in the specified graph. - */ - public void print(Graph graph, boolean shortNames) { - // graph.getNodes() returns all the graph's nodes, not just "roots" - for (Node n : graph.getNodes()) { - if (n != null) { - printNode(n, shortNames); - } - } - } - - /** - * Prints a single node and edges for all its inputs and successors. - */ - public void printNode(Node node, boolean shortNames) { - if (omittedClasses.contains(node.getClass())) { - return; - } - int id = node.id(); - String name = "n" + id; - NodeArray inputs = node.inputs(); - NodeArray successors = node.successors(); - - String color = classColors.get(node.getClass()); - - if (shortNames) { - printNode(name, node.id(), excapeLabel(node.shortName()), color, inputs.size(), successors.size()); - } else { - printNode(name, node.id(), excapeLabel(node.toString()), color, inputs.size(), successors.size()); - } - - for (int i = 0; i < successors.size(); ++i) { - Node successor = successors.get(i); - if (successor != Node.Null && !omittedClasses.contains(successor.getClass())) { - printControlEdge(id, i, successor.id()); - } - } - - for (int i = 0; i < inputs.size(); ++i) { - Node input = inputs.get(i); - if (input != Node.Null && !omittedClasses.contains(input.getClass())) { - if (node.getClass().getSimpleName().equals("FrameState") && input.getClass().getSimpleName().equals("Local")) { - continue; - } - printDataEdge(id, i, input.id()); - } - } - } - - private void printNode(String name, Number number, String label, String color, int ninputs, int nsuccessors) { - int minWidth = Math.min(1 + label.length() / 3, 10); - minWidth = Math.max(minWidth, Math.max(ninputs + 1, nsuccessors + 1)); - out.println(name + " [shape=plaintext,"); - out.println(" label=< "); - - printPort("predecessors", "rosybrown1"); - - for (int i = 1; i < minWidth - ninputs; i++) { - printEmptyPort(); - } - - for (int i = 0; i < ninputs; i++) { - printPort("in" + i, "lightgrey"); - } - - if (number != null) { - label = "" + number + " " + label; - } - - out.println(" "); - - for (int i = 0; i < nsuccessors; i++) { - printPort("succ" + i, "rosybrown1"); - } - - for (int i = 1; i < minWidth - nsuccessors; i++) { - printEmptyPort(); - } - - printPort("usages", "lightgrey"); - - out.println("
" + label + "
>]; "); - } - - private static String excapeLabel(String label) { - label = label.replace("&", "&"); - label = label.replace("<", "<"); - label = label.replace(">", ">"); - label = label.replace("\"", """); - return label; - } - - private void printPort(String name, String color) { - out.print("
"); - } - - private void printEmptyPort() { - out.print("
"); - } - - private void printControlEdge(int from, int fromPort, int to) { - out.println("n" + from + ":succ" + fromPort + ":s -> n" + to + ":predecessors:n [color=red, weight=2];"); - } - - private void printDataEdge(int from, int fromPort, int to) { - out.println("n" + to + ":usages:s -> n" + from + ":in" + fromPort + ":n [color=black,dir=back];"); - } - -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.graphviz/src/com/oracle/graal/graph/vis/GraphvizRunner.java --- a/graal/com.oracle.max.graal.graphviz/src/com/oracle/graal/graph/vis/GraphvizRunner.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,91 +0,0 @@ -/* - * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.graph.vis; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -/** - * Provides functionality to process graphs in the DOT language with a Graphviz tool and obtain the generated output. - */ -public class GraphvizRunner { - - public static final String DOT_LAYOUT = "dot"; - - /** - * Processes data from an input stream with a Graphviz tool such as {@code dot}, writing output in the specified - * format to the given output stream. The method waits for the executed tool to finish and then returns its exit - * code. - * - * @param layout - * The Graphviz layouter to use (e.g. "dot"). - * @param in - * Stream to read input from. - * @param out - * Stream to write output to. - * @param format - * Desired output format (-T parameter). - * @return Exit code of the called utility. - * @throws IOException - * When the process can not be started (e.g. Graphviz missing) or reading/writing a stream fails. - */ - public static int process(String layout, InputStream in, OutputStream out, String format) throws IOException { - byte[] buffer = new byte[4096]; - - // create and start process - ProcessBuilder pb = new ProcessBuilder("dot", "-T", format, "-K", layout); - Process p = pb.start(); - - // write data from in to stdin - OutputStream stdin = p.getOutputStream(); - transfer(buffer, in, stdin); - stdin.close(); - in.close(); - - // read output from stdout and write to out - InputStream stdout = p.getInputStream(); - transfer(buffer, stdout, out); - stdout.close(); - - // wait for process to terminate - for (;;) { - try { - return p.waitFor(); - } catch (InterruptedException e) { - // ignore - } - } - } - - /** - * Reads all data from an {@link InputStream} and writes it to an {@link OutputStream}, using the provided buffer. - */ - private static void transfer(byte[] buffer, InputStream in, OutputStream out) throws IOException { - int count; - while ((count = in.read(buffer, 0, buffer.length)) != -1) { - out.write(buffer, 0, count); - } - in.close(); - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.graphviz/src/com/oracle/max/graal/graphviz/GraphvizPrinter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.graphviz/src/com/oracle/max/graal/graphviz/GraphvizPrinter.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.graphviz; + +import java.awt.Color; +import java.io.OutputStream; +import java.io.PrintStream; +import java.util.HashMap; +import java.util.HashSet; + +import com.oracle.max.graal.graph.Graph; +import com.oracle.max.graal.graph.Node; +import com.oracle.max.graal.graph.NodeArray; + +/** + * Generates a representation of {@link Node Nodes} or entire {@link Graph Graphs} in the DOT language that can be + * visualized with Graphviz. + */ +public class GraphvizPrinter { + + public static final Color NODE_BGCOLOR = Color.WHITE; + private static final String NODE_BGCOLOR_STRING = formatColorString(NODE_BGCOLOR); + + private static String formatColorString(Color c) { + return String.format("#%02x%02x%02x%02x", c.getRed(), c.getGreen(), c.getBlue(), c.getAlpha()); + } + + private final PrintStream out; + private final HashSet> omittedClasses = new HashSet>(); + private final HashMap, String> classColors = new HashMap, String>(); + + /** + * Creates a new {@link GraphvizPrinter} that writes to the specified output stream. + */ + public GraphvizPrinter(OutputStream out) { + this.out = new PrintStream(out); + } + + public void addOmittedClass(Class clazz) { + omittedClasses.add(clazz); + } + + public void addClassColor(Class clazz, String color) { + classColors.put(clazz, color); + } + + /** + * Opens a graph with the specified title (label). Call this before printing any nodes, but not more than once + * without calling {@link #end()} first. + * + * @param title + * The graph's label. + */ + public void begin(String title) { + out.println("digraph g {"); + if (title != null) { + out.println(" label=\"" + title + "\";"); + } + } + + /** + * Closes the graph. No nodes should be printed afterwards. Another graph can be opened with {@link #begin(String)}, + * but many Graphviz output plugins ignore additional graphs in their input. + */ + public void end() { + out.println("}"); + } + + /** + * Prints all nodes and edges in the specified graph. + */ + public void print(Graph graph, boolean shortNames) { + // graph.getNodes() returns all the graph's nodes, not just "roots" + for (Node n : graph.getNodes()) { + if (n != null) { + printNode(n, shortNames); + } + } + } + + /** + * Prints a single node and edges for all its inputs and successors. + */ + public void printNode(Node node, boolean shortNames) { + if (omittedClasses.contains(node.getClass())) { + return; + } + int id = node.id(); + String name = "n" + id; + NodeArray inputs = node.inputs(); + NodeArray successors = node.successors(); + + String color = classColors.get(node.getClass()); + + if (shortNames) { + printNode(name, node.id(), excapeLabel(node.shortName()), color, inputs.size(), successors.size()); + } else { + printNode(name, node.id(), excapeLabel(node.toString()), color, inputs.size(), successors.size()); + } + + for (int i = 0; i < successors.size(); ++i) { + Node successor = successors.get(i); + if (successor != Node.Null && !omittedClasses.contains(successor.getClass())) { + printControlEdge(id, i, successor.id()); + } + } + + for (int i = 0; i < inputs.size(); ++i) { + Node input = inputs.get(i); + if (input != Node.Null && !omittedClasses.contains(input.getClass())) { + if (node.getClass().getSimpleName().equals("FrameState") && input.getClass().getSimpleName().equals("Local")) { + continue; + } + printDataEdge(id, i, input.id()); + } + } + } + + private void printNode(String name, Number number, String label, String color, int ninputs, int nsuccessors) { + int minWidth = Math.min(1 + label.length() / 3, 10); + minWidth = Math.max(minWidth, Math.max(ninputs + 1, nsuccessors + 1)); + out.println(name + " [shape=plaintext,"); + out.println(" label=< "); + + printPort("predecessors", "rosybrown1"); + + for (int i = 1; i < minWidth - ninputs; i++) { + printEmptyPort(); + } + + for (int i = 0; i < ninputs; i++) { + printPort("in" + i, "lightgrey"); + } + + if (number != null) { + label = "" + number + " " + label; + } + + out.println(" "); + + for (int i = 0; i < nsuccessors; i++) { + printPort("succ" + i, "rosybrown1"); + } + + for (int i = 1; i < minWidth - nsuccessors; i++) { + printEmptyPort(); + } + + printPort("usages", "lightgrey"); + + out.println("
" + label + "
>]; "); + } + + private static String excapeLabel(String label) { + label = label.replace("&", "&"); + label = label.replace("<", "<"); + label = label.replace(">", ">"); + label = label.replace("\"", """); + return label; + } + + private void printPort(String name, String color) { + out.print("
"); + } + + private void printEmptyPort() { + out.print("
"); + } + + private void printControlEdge(int from, int fromPort, int to) { + out.println("n" + from + ":succ" + fromPort + ":s -> n" + to + ":predecessors:n [color=red, weight=2];"); + } + + private void printDataEdge(int from, int fromPort, int to) { + out.println("n" + to + ":usages:s -> n" + from + ":in" + fromPort + ":n [color=black,dir=back];"); + } + +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.graphviz/src/com/oracle/max/graal/graphviz/GraphvizRunner.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.graphviz/src/com/oracle/max/graal/graphviz/GraphvizRunner.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.graphviz; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +/** + * Provides functionality to process graphs in the DOT language with a Graphviz tool and obtain the generated output. + */ +public class GraphvizRunner { + + public static final String DOT_LAYOUT = "dot"; + + /** + * Processes data from an input stream with a Graphviz tool such as {@code dot}, writing output in the specified + * format to the given output stream. The method waits for the executed tool to finish and then returns its exit + * code. + * + * @param layout + * The Graphviz layouter to use (e.g. "dot"). + * @param in + * Stream to read input from. + * @param out + * Stream to write output to. + * @param format + * Desired output format (-T parameter). + * @return Exit code of the called utility. + * @throws IOException + * When the process can not be started (e.g. Graphviz missing) or reading/writing a stream fails. + */ + public static int process(String layout, InputStream in, OutputStream out, String format) throws IOException { + byte[] buffer = new byte[4096]; + + // create and start process + ProcessBuilder pb = new ProcessBuilder("dot", "-T", format, "-K", layout); + Process p = pb.start(); + + // write data from in to stdin + OutputStream stdin = p.getOutputStream(); + transfer(buffer, in, stdin); + stdin.close(); + in.close(); + + // read output from stdout and write to out + InputStream stdout = p.getInputStream(); + transfer(buffer, stdout, out); + stdout.close(); + + // wait for process to terminate + for (;;) { + try { + return p.waitFor(); + } catch (InterruptedException e) { + // ignore + } + } + } + + /** + * Reads all data from an {@link InputStream} and writes it to an {@link OutputStream}, using the provided buffer. + */ + private static void transfer(byte[] buffer, InputStream in, OutputStream out) throws IOException { + int count; + while ((count = in.read(buffer, 0, buffer.length)) != -1) { + out.write(buffer, 0, count); + } + in.close(); + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.graphviz/test/com/oracle/graal/graph/vis/GraphvizTest.java --- a/graal/com.oracle.max.graal.graphviz/test/com/oracle/graal/graph/vis/GraphvizTest.java Wed Jun 08 08:45:47 2011 +0200 +++ b/graal/com.oracle.max.graal.graphviz/test/com/oracle/graal/graph/vis/GraphvizTest.java Wed Jun 08 08:59:54 2011 +0200 @@ -31,8 +31,10 @@ import org.junit.Test; -import com.oracle.graal.graph.Graph; -import com.oracle.graal.graph.Node; +import com.oracle.max.graal.graph.Graph; +import com.oracle.max.graal.graph.Node; +import com.oracle.max.graal.graphviz.GraphvizPrinter; +import com.oracle.max.graal.graphviz.GraphvizRunner; /** * Tests for the Graphviz graph generator. Needs Graphviz (more specifically, dot) installed to verify produced output. diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/Compiler.java --- a/graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/Compiler.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.runtime; - -import com.sun.c1x.*; - -public interface Compiler { - - VMEntries getVMEntries(); - VMExits getVMExits(); - C1XCompiler getCompiler(); - -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/CompilerImpl.java --- a/graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/CompilerImpl.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,199 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.runtime; - -import java.io.*; -import java.lang.management.*; -import java.net.*; - -import com.oracle.graal.runtime.logging.*; -import com.oracle.graal.runtime.server.*; -import com.oracle.max.asm.target.amd64.*; -import com.sun.c1x.*; -import com.sun.cri.ci.*; -import com.sun.cri.ri.*; -import com.sun.cri.xir.*; - -/** - * Singleton class holding the instance of the C1XCompiler. - */ -public final class CompilerImpl implements Compiler, Remote { - - private static Compiler theInstance; - private static boolean PrintGCStats = false; - - public static Compiler getInstance() { - return theInstance; - } - - public static void initialize() { - if (theInstance != null) { - throw new IllegalStateException("Compiler already initialized"); - } - - String remote = System.getProperty("c1x.remote"); - if (remote != null) { - // remote compilation (will not create a local Compiler) - try { - System.out.println("C1X compiler started in client/server mode, server: " + remote); - Socket socket = new Socket(remote, 1199); - ReplacingStreams streams = new ReplacingStreams(socket.getOutputStream(), socket.getInputStream()); - streams.getInvocation().sendResult(new VMEntriesNative()); - - theInstance = (Compiler) streams.getInvocation().waitForResult(false); - } catch (IOException e1) { - System.out.println("Connection to compilation server FAILED."); - throw new RuntimeException(e1); - } catch (ClassNotFoundException e2) { - System.out.println("Connection to compilation server FAILED."); - throw new RuntimeException(e2); - } - } else { - // ordinary local compilation - theInstance = new CompilerImpl(null); - Runtime.getRuntime().addShutdownHook(new ShutdownThread()); - } - } - - public static Compiler initializeServer(VMEntries entries) { - assert theInstance == null; - theInstance = new CompilerImpl(entries); - Runtime.getRuntime().addShutdownHook(new ShutdownThread()); - return theInstance; - } - - public static class ShutdownThread extends Thread { - - @Override - public void run() { - VMExitsNative.compileMethods = false; - if (C1XOptions.PrintMetrics) { - C1XMetrics.print(); - } - if (C1XOptions.PrintTimers) { - C1XTimers.print(); - } - if (PrintGCStats) { - printGCStats(); - } - } - } - - public static void printGCStats() { - long totalGarbageCollections = 0; - long garbageCollectionTime = 0; - - for (GarbageCollectorMXBean gc : ManagementFactory.getGarbageCollectorMXBeans()) { - long count = gc.getCollectionCount(); - if (count >= 0) { - totalGarbageCollections += count; - } - - long time = gc.getCollectionTime(); - if (time >= 0) { - garbageCollectionTime += time; - } - } - - System.out.println("Total Garbage Collections: " + totalGarbageCollections); - System.out.println("Total Garbage Collection Time (ms): " + garbageCollectionTime); - } - - private final VMEntries vmEntries; - private final VMExits vmExits; - private C1XCompiler compiler; - - private final HotSpotRuntime runtime; - private final CiTarget target; - private final RiXirGenerator generator; - private final RiRegisterConfig registerConfig; - - private CompilerImpl(VMEntries entries) { - - // initialize VMEntries - if (entries == null) { - entries = new VMEntriesNative(); - } - - // initialize VMExits - VMExits exits = new VMExitsNative(this); - - // logging, etc. - if (CountingProxy.ENABLED) { - exits = CountingProxy.getProxy(VMExits.class, exits); - entries = CountingProxy.getProxy(VMEntries.class, entries); - } - if (Logger.ENABLED) { - exits = LoggingProxy.getProxy(VMExits.class, exits); - entries = LoggingProxy.getProxy(VMEntries.class, entries); - } - - // set the final fields - vmEntries = entries; - vmExits = exits; - - // initialize compiler and C1XOptions - HotSpotVMConfig config = vmEntries.getConfiguration(); - config.check(); - - // these options are important - c1x4hotspot will not generate correct code without them - C1XOptions.GenSpecialDivChecks = true; - C1XOptions.NullCheckUniquePc = true; - C1XOptions.InvokeSnippetAfterArguments = true; - C1XOptions.StackShadowPages = config.stackShadowPages; - - runtime = new HotSpotRuntime(config, this); - registerConfig = runtime.globalStubRegConfig; - - final int wordSize = 8; - final int stackFrameAlignment = 16; - target = new HotSpotTarget(new AMD64(), true, wordSize, stackFrameAlignment, config.vmPageSize, wordSize, true); - - RiXirGenerator generator = new HotSpotXirGenerator(config, target, registerConfig, this); - if (Logger.ENABLED) { - this.generator = LoggingProxy.getProxy(RiXirGenerator.class, generator); - } else { - this.generator = generator; - } - - } - - @Override - public C1XCompiler getCompiler() { - if (compiler == null) { - compiler = new C1XCompiler(runtime, target, generator, registerConfig); - } - return compiler; - } - - @Override - public VMEntries getVMEntries() { - return vmEntries; - } - - @Override - public VMExits getVMExits() { - return vmExits; - } - -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/CompilerObject.java --- a/graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/CompilerObject.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.runtime; - -import java.io.*; - - -/** - * Parent class for all HotSpot Ri... types. - */ -public abstract class CompilerObject implements Serializable { - protected final Compiler compiler; - - protected CompilerObject(Compiler compiler) { - this.compiler = compiler; - } - -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/HotSpotConstantPool.java --- a/graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/HotSpotConstantPool.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,145 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.runtime; - -import java.io.*; -import java.util.*; - -import com.sun.cri.ri.*; - -/** - * Implementation of RiConstantPool for HotSpot. - */ -public class HotSpotConstantPool extends CompilerObject implements RiConstantPool { - - private final long vmId; - - private final FastLRUIntCache methodCache = new FastLRUIntCache(); - private final FastLRUIntCache fieldCache = new FastLRUIntCache(); - private final FastLRUIntCache typeCache = new FastLRUIntCache(); - - public static class FastLRUIntCache implements Serializable { - - private static final int InitialCapacity = 4; - private int lastKey; - private T lastObject; - - private int[] keys; - private Object[] objects; - private int count; - - @SuppressWarnings("unchecked") - private T access(int index) { - return (T) objects[index]; - } - - public T get(int key) { - if (key == lastKey) { - return lastObject; - } else if (count > 1) { - for (int i = 0; i < count; ++i) { - if (keys[i] == key) { - lastObject = access(i); - lastKey = key; - return lastObject; - } - } - } - return null; - } - - public void add(int key, T object) { - count++; - if (count == 1) { - lastKey = key; - lastObject = object; - } else { - ensureSize(); - keys[count - 1] = key; - objects[count - 1] = object; - if (count == 2) { - keys[0] = lastKey; - objects[0] = lastObject; - } - lastKey = key; - lastObject = object; - } - } - - private void ensureSize() { - if (keys == null) { - keys = new int[InitialCapacity]; - objects = new Object[InitialCapacity]; - } else if (count > keys.length) { - keys = Arrays.copyOf(keys, keys.length * 2); - objects = Arrays.copyOf(objects, objects.length * 2); - } - } - } - - public HotSpotConstantPool(Compiler compiler, long vmId) { - super(compiler); - this.vmId = vmId; - } - - @Override - public Object lookupConstant(int cpi) { - Object constant = compiler.getVMEntries().RiConstantPool_lookupConstant(vmId, cpi); - return constant; - } - - @Override - public RiSignature lookupSignature(int cpi) { - return compiler.getVMEntries().RiConstantPool_lookupSignature(vmId, cpi); - } - - @Override - public RiMethod lookupMethod(int cpi, int byteCode) { - RiMethod result = methodCache.get(cpi); - if (result == null) { - result = compiler.getVMEntries().RiConstantPool_lookupMethod(vmId, cpi, (byte) byteCode); - methodCache.add(cpi, result); - } - return result; - } - - @Override - public RiType lookupType(int cpi, int opcode) { - RiType result = typeCache.get(cpi); - if (result == null) { - result = compiler.getVMEntries().RiConstantPool_lookupType(vmId, cpi); - typeCache.add(cpi, result); - } - return result; - } - - @Override - public RiField lookupField(int cpi, int opcode) { - RiField result = fieldCache.get(cpi); - if (result == null) { - result = compiler.getVMEntries().RiConstantPool_lookupField(vmId, cpi, (byte) opcode); - fieldCache.add(cpi, result); - } - return result; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/HotSpotExceptionHandler.java --- a/graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/HotSpotExceptionHandler.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.runtime; - -import com.sun.cri.ri.*; - - -public class HotSpotExceptionHandler extends CompilerObject implements RiExceptionHandler { - private int startBci; - private int endBci; - private int handlerBci; - private int catchClassIndex; - private RiType catchClass; - - public HotSpotExceptionHandler() { - super(null); - } - - @Override - public int startBCI() { - return startBci; - } - - @Override - public int endBCI() { - return endBci; - } - - @Override - public int handlerBCI() { - return handlerBci; - } - - @Override - public int catchTypeCPI() { - return catchClassIndex; - } - - @Override - public boolean isCatchAll() { - return catchClassIndex == 0; - } - - @Override - public RiType catchType() { - return catchClass; - } - -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/HotSpotField.java --- a/graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/HotSpotField.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,136 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.oracle.graal.runtime; - -import java.lang.reflect.*; - -import com.sun.c1x.*; -import com.sun.cri.ci.CiConstant; -import com.sun.cri.ci.CiKind; -import com.sun.cri.ri.RiField; -import com.sun.cri.ri.RiType; - -/** - * Represents a field in a HotSpot type. - */ -public class HotSpotField extends CompilerObject implements RiField { - - private final RiType holder; - private final String name; - private final RiType type; - private final int offset; - private final int accessFlags; - private CiConstant constant; - - public HotSpotField(Compiler compiler, RiType holder, String name, RiType type, int offset, int accessFlags) { - super(compiler); - this.holder = holder; - this.name = name; - this.type = type; - this.offset = offset; - this.accessFlags = accessFlags; - } - - @Override - public int accessFlags() { - return accessFlags; - } - - @Override - public CiConstant constantValue(CiConstant receiver) { - if (receiver == null) { - if (constant == null && holder.isResolved() && holder.isSubtypeOf(compiler.getVMEntries().getType(C1XOptions.class))) { - Field f; - try { - f = C1XOptions.class.getField(name); - } catch (SecurityException e1) { - return null; - } catch (NoSuchFieldException e1) { - return null; - } - f.setAccessible(true); - if (Modifier.isStatic(f.getModifiers())) { - CiKind kind = CiKind.fromJavaClass(f.getType()); - Object value; - try { - value = f.get(null); - } catch (IllegalArgumentException e) { - return null; - } catch (IllegalAccessException e) { - return null; - } - constant = CiConstant.forBoxed(kind, value); - } - } - - // Constant part only valid for static fields. - return constant; - } - return null; - } - - @Override - public RiType holder() { - return holder; - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof HotSpotField) { - HotSpotField other = (HotSpotField) obj; - return other.offset == offset && other.holder.equals(holder()); - } - return false; - } - - @Override - public boolean isResolved() { - return offset != -1; - } - - @Override - public CiKind kind() { - return type().kind(); - } - - @Override - public String name() { - return name; - } - - @Override - public RiType type() { - return type; - } - - public int offset() { - return offset; - } - - @Override - public String toString() { - return "HotSpotField<" + holder.name() + "." + name + ">"; - } - -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/HotSpotMethod.java --- a/graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/HotSpotMethod.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.runtime; - -import com.sun.cri.ri.*; - - -public abstract class HotSpotMethod extends CompilerObject implements RiMethod { - - protected RiType holder; - protected String name; - - protected HotSpotMethod(Compiler compiler) { - super(compiler); - } - - @Override - public final RiType holder() { - return holder; - } - - @Override - public final String name() { - return name; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/HotSpotMethodResolved.java --- a/graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/HotSpotMethodResolved.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,192 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.runtime; - -import java.lang.reflect.*; - -import com.sun.cri.ci.*; -import com.sun.cri.ri.*; - -/** - * Implementation of RiMethod for resolved HotSpot methods. - */ -public final class HotSpotMethodResolved extends HotSpotMethod { - - private final long vmId; - - // cached values - private byte[] code; - private int accessFlags = -1; - private int maxLocals = -1; - private int maxStackSize = -1; - private RiExceptionHandler[] exceptionHandlers; - private RiSignature signature; - private Boolean hasBalancedMonitors; - - public HotSpotMethodResolved(Compiler compiler, long vmId, String name) { - super(compiler); - this.vmId = vmId; - this.name = name; - this.holder = compiler.getVMEntries().RiMethod_holder(vmId); - } - - @Override - public int accessFlags() { - if (accessFlags == -1) { - accessFlags = compiler.getVMEntries().RiMethod_accessFlags(vmId); - } - return accessFlags; - } - - @Override - public boolean canBeStaticallyBound() { - return isLeafMethod() || Modifier.isStatic(accessFlags()); - } - - @Override - public byte[] code() { - if (code == null) { - code = compiler.getVMEntries().RiMethod_code(vmId); - } - return code; - } - - @Override - public RiExceptionHandler[] exceptionHandlers() { - if (exceptionHandlers == null) { - exceptionHandlers = compiler.getVMEntries().RiMethod_exceptionHandlers(vmId); - } - return exceptionHandlers; - } - - @Override - public boolean hasBalancedMonitors() { - if (hasBalancedMonitors == null) { - hasBalancedMonitors = compiler.getVMEntries().RiMethod_hasBalancedMonitors(vmId); - } - return hasBalancedMonitors; - } - - @Override - public boolean isClassInitializer() { - return "".equals(name); - } - - @Override - public boolean isConstructor() { - return "".equals(name); - } - - @Override - public boolean isLeafMethod() { - return Modifier.isFinal(accessFlags()) || Modifier.isPrivate(accessFlags()); - } - - @Override - public boolean isOverridden() { - throw new UnsupportedOperationException("isOverridden"); - } - - @Override - public boolean noSafepoints() { - return false; - } - - @Override - public boolean isResolved() { - return true; - } - - @Override - public String jniSymbol() { - throw new UnsupportedOperationException("jniSymbol"); - } - - public CiBitMap[] livenessMap() { - return null; - } - - @Override - public int maxLocals() { - if (maxLocals == -1) { - maxLocals = compiler.getVMEntries().RiMethod_maxLocals(vmId); - } - return maxLocals; - } - - @Override - public int maxStackSize() { - if (maxStackSize == -1) { - maxStackSize = compiler.getVMEntries().RiMethod_maxStackSize(vmId); - } - return maxStackSize; - } - - @Override - public RiMethodProfile methodData() { - return null; - } - - @Override - public StackTraceElement toStackTraceElement(int bci) { - return CiUtil.toStackTraceElement(this, bci); - } - - public RiMethod uniqueConcreteMethod() { - return compiler.getVMEntries().RiMethod_uniqueConcreteMethod(vmId); - } - - @Override - public RiSignature signature() { - if (signature == null) { - signature = new HotSpotSignature(compiler, compiler.getVMEntries().RiMethod_signature(vmId)); - } - return signature; - } - - @Override - public String toString() { - return "HotSpotMethod<" + holder().name() + ". " + name + ">"; - } - - public boolean hasCompiledCode() { - // TODO: needs a VMEntries to go cache the result of that method. - // This isn't used by GRAAL for now, so this is enough. - return false; - } - - @Override - public RiType accessor() { - return null; - } - - @Override - public int intrinsic() { - return 0; - } - - @Override - public boolean minimalDebugInfo() { - return false; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/HotSpotMethodUnresolved.java --- a/graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/HotSpotMethodUnresolved.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,158 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.runtime; - -import com.sun.cri.ci.*; -import com.sun.cri.ri.*; - -/** - * Implementation of RiMethod for unresolved HotSpot methods. - */ -public final class HotSpotMethodUnresolved extends HotSpotMethod { - private final RiSignature signature; - - public HotSpotMethodUnresolved(Compiler compiler, String name, String signature, RiType holder) { - super(compiler); - this.name = name; - this.holder = holder; - this.signature = new HotSpotSignature(compiler, signature); - } - - @Override - public RiSignature signature() { - return signature; - } - - @Override - public boolean isResolved() { - return false; - } - - @Override - public byte[] code() { - throw unresolved("code"); - } - - @Override - public RiMethodProfile methodData() { - throw unresolved("methodData"); - } - - @Override - public String jniSymbol() { - throw unresolved("jniSymbol"); - } - - @Override - public int maxLocals() { - throw unresolved("maxLocals"); - } - - @Override - public int maxStackSize() { - throw unresolved("maxStackSize"); - } - - @Override - public boolean hasBalancedMonitors() { - throw unresolved("hasBalancedMonitors"); - } - - @Override - public int accessFlags() { - throw unresolved("accessFlags"); - } - - @Override - public boolean isLeafMethod() { - throw unresolved("isLeafMethod"); - } - - @Override - public boolean isClassInitializer() { - return "".equals(name); - } - - @Override - public boolean isConstructor() { - return "".equals(name); - } - - @Override - public boolean isOverridden() { - throw unresolved("isOverridden"); - } - - @Override - public boolean noSafepoints() { - return false; - } - - @Override - public CiBitMap[] livenessMap() { - return null; - } - - @Override - public StackTraceElement toStackTraceElement(int bci) { - return CiUtil.toStackTraceElement(this, bci); - } - - @Override - public boolean canBeStaticallyBound() { - throw unresolved("canBeStaticallyBound"); - } - - @Override - public RiExceptionHandler[] exceptionHandlers() { - throw unresolved("exceptionHandlers"); - } - - @Override - public boolean minimalDebugInfo() { - throw unresolved("minimalDebugInfo"); - } - - private CiUnresolvedException unresolved(String operation) { - return new CiUnresolvedException(operation + " not defined for unresolved method " + name); - } - - @Override - public String toString() { - return "HotSpotMethod<" + holder.name() + ". " + name + ", unresolved>"; - } - - public boolean hasCompiledCode() { - return false; - } - - @Override - public RiType accessor() { - return null; - } - - @Override - public int intrinsic() { - return 0; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/HotSpotOptions.java --- a/graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/HotSpotOptions.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,101 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.oracle.graal.runtime; - -import java.lang.reflect.*; - -import com.oracle.graal.runtime.logging.*; -import com.sun.c1x.*; - -public class HotSpotOptions { - - public static void setDefaultOptions() { - C1XOptions.CommentedAssembly = false; - C1XOptions.MethodEndBreakpointGuards = 2; - C1XOptions.ResolveClassBeforeStaticInvoke = false; - } - - public static boolean setOption(String option) { - if (option.length() == 0) { - return false; - } - - Object value = null; - String fieldName = null; - String valueString = null; - - char first = option.charAt(0); - if (first == '+' || first == '-') { - fieldName = option.substring(1); - value = (first == '+'); - } else { - int index = option.indexOf('='); - if (index == -1) { - return false; - } - fieldName = option.substring(0, index); - valueString = option.substring(index + 1); - } - - Field f; - try { - f = C1XOptions.class.getField(fieldName); - - if (value == null) { - if (f.getType() == Float.TYPE) { - value = Float.parseFloat(valueString); - } else if (f.getType() == Double.TYPE) { - value = Double.parseDouble(valueString); - } else if (f.getType() == Integer.TYPE) { - value = Integer.parseInt(valueString); - } else if (f.getType() == Boolean.TYPE) { - value = Boolean.parseBoolean(valueString); - } else if (f.getType() == String.class) { - value = valueString; - } - } - if (value != null) { - f.set(null, value); - //Logger.info("Set option " + fieldName + " to " + value); - } else { - Logger.info("Wrong value \"" + valueString + "\" for option " + fieldName); - return false; - } - } catch (SecurityException e) { - Logger.info("Security exception when setting option " + option); - return false; - } catch (NoSuchFieldException e) { - Logger.info("Could not find option " + fieldName); - return false; - } catch (IllegalArgumentException e) { - Logger.info("Illegal value for option " + option); - return false; - } catch (IllegalAccessException e) { - Logger.info("Illegal access exception when setting option " + option); - return false; - } - - return true; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/HotSpotProxy.java --- a/graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/HotSpotProxy.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,92 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.runtime; - -/** - * Provides methods to classify the HotSpot-internal identifiers. - */ -public final class HotSpotProxy { - - private HotSpotProxy() { - } - - private enum CompilerObjectType { - // this enum needs to have the same values as the one in c1x_Compiler.hpp - STUB(0x100000000000000L), - METHOD(0x200000000000000L), - CLASS(0x300000000000000L), - SYMBOL(0x400000000000000L), - CONSTANT_POOL(0x500000000000000L), - CONSTANT(0x600000000000000L), - TYPE_MASK(0xf00000000000000L), - DUMMY_CONSTANT(0x6ffffffffffffffL); - - public final long bits; - - CompilerObjectType(long bits) { - this.bits = bits; - } - } - - public static final Long DUMMY_CONSTANT_OBJ = CompilerObjectType.DUMMY_CONSTANT.bits; - - private static boolean isType(long id, CompilerObjectType type) { - return (id & CompilerObjectType.TYPE_MASK.bits) == type.bits; - } - - public static boolean isStub(long id) { - return isType(id, CompilerObjectType.STUB); - } - - public static boolean isMethod(long id) { - return isType(id, CompilerObjectType.METHOD); - } - - public static boolean isClass(long id) { - return isType(id, CompilerObjectType.CLASS); - } - - public static boolean isSymbol(long id) { - return isType(id, CompilerObjectType.SYMBOL); - } - - public static boolean isConstantPool(long id) { - return isType(id, CompilerObjectType.CONSTANT_POOL); - } - - public static boolean isConstant(long id) { - return isType(id, CompilerObjectType.CONSTANT_POOL); - } - - public static String toString(long id) { - CompilerObjectType type = null; - for (CompilerObjectType t : CompilerObjectType.values()) { - if ((id & CompilerObjectType.TYPE_MASK.bits) == t.bits) { - type = t; - } - } - long num = id & ~CompilerObjectType.TYPE_MASK.bits; - return type + " " + num; - } - -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/HotSpotRegisterConfig.java --- a/graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/HotSpotRegisterConfig.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,209 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.runtime; - -import static com.oracle.max.asm.target.amd64.AMD64.*; - -import java.util.*; - -import com.oracle.max.asm.target.amd64.*; -import com.sun.c1x.util.*; -import com.sun.cri.ci.*; -import com.sun.cri.ci.CiCallingConvention.Type; -import com.sun.cri.ci.CiRegister.RegisterFlag; -import com.sun.cri.ri.*; - -public class HotSpotRegisterConfig implements RiRegisterConfig { - - // be careful - the contents of this array are duplicated in c1x_CodeInstaller.cpp - private final CiRegister[] allocatable = { - rax, rbx, rcx, rdx, rsi, rdi, r8, r9, /* r10, */r11, r12, r13, r14, /*r15*/ - xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, - xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15 - }; - - private final EnumMap categorized = CiRegister.categorize(allocatable); - - private final RiRegisterAttributes[] attributesMap; - - @Override - public CiRegister[] getAllocatableRegisters() { - return allocatable; - } - - @Override - public EnumMap getCategorizedAllocatableRegisters() { - return categorized; - } - - @Override - public RiRegisterAttributes[] getAttributesMap() { - return attributesMap; - } - - private final CiRegister[] generalParameterRegisters; - private final CiRegister[] xmmParameterRegisters = {xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7}; - private final CiRegister[] allParameterRegisters; - - private final CiRegister[] rsaRegs = { - rax, rcx, rdx, rbx, rsp, rbp, rsi, rdi, - r8, r9, r10, r11, r12, r13, r14, r15, - xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, - xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15 - }; - - private final CiCalleeSaveArea registerSaveArea; - - - public HotSpotRegisterConfig(HotSpotVMConfig config, boolean globalStubConfig) { - if (config.windowsOs) { - generalParameterRegisters = new CiRegister[] {rdx, r8, r9, rdi, rsi, rcx}; - } else { - generalParameterRegisters = new CiRegister[] {rsi, rdx, rcx, r8, r9, rdi}; - } - - if (globalStubConfig) { - registerSaveArea = new CiCalleeSaveArea(-1, 8, rsaRegs); - } else { - registerSaveArea = CiCalleeSaveArea.EMPTY; - } - - attributesMap = RiRegisterAttributes.createMap(this, AMD64.allRegisters); - allParameterRegisters = Arrays.copyOf(generalParameterRegisters, generalParameterRegisters.length + xmmParameterRegisters.length); - System.arraycopy(xmmParameterRegisters, 0, allParameterRegisters, generalParameterRegisters.length, xmmParameterRegisters.length); - } - - @Override - public CiRegister[] getCallerSaveRegisters() { - return getAllocatableRegisters(); - } - - @Override - public CiRegister getRegisterForRole(int index) { - throw new UnsupportedOperationException(); - } - - @Override - public CiCallingConvention getCallingConvention(Type type, CiKind[] parameters, CiTarget target) { - if (type == Type.NativeCall) { - throw new UnsupportedOperationException(); - } - return callingConvention(parameters, type, target); - } - - public CiRegister[] getCallingConventionRegisters(Type type, RegisterFlag flag) { - return allParameterRegisters; - } - - private CiCallingConvention callingConvention(CiKind[] types, Type type, CiTarget target) { - CiValue[] locations = new CiValue[types.length]; - - int currentGeneral = 0; - int currentXMM = 0; - int currentStackIndex = 0; - - for (int i = 0; i < types.length; i++) { - final CiKind kind = types[i]; - - switch (kind) { - case Byte: - case Boolean: - case Short: - case Char: - case Int: - case Long: - case Word: - case Object: - if (currentGeneral < generalParameterRegisters.length) { - CiRegister register = generalParameterRegisters[currentGeneral++]; - locations[i] = register.asValue(kind); - } - break; - case Float: - case Double: - if (currentXMM < xmmParameterRegisters.length) { - CiRegister register = xmmParameterRegisters[currentXMM++]; - locations[i] = register.asValue(kind); - } - break; - default: - throw Util.shouldNotReachHere(); - } - - if (locations[i] == null) { - // we need to adjust for the frame pointer stored on the stack, which shifts incoming arguments by one slot - locations[i] = CiStackSlot.get(kind.stackKind(), currentStackIndex + (type.out ? 0 : 1), !type.out); - currentStackIndex += target.spillSlots(kind); - } - } - - return new CiCallingConvention(locations, currentStackIndex * target.spillSlotSize); - } - - @Override - public CiRegister getReturnRegister(CiKind kind) { - switch (kind) { - case Boolean: - case Byte: - case Char: - case Short: - case Int: - case Long: - case Object: - case Word: - return rax; - case Float: - case Double: - return xmm0; - case Void: - case Illegal: - return null; - default: - throw new UnsupportedOperationException("no return register for type " + kind); - } - } - - @Override - public CiRegister getScratchRegister() { - return r10; - } - - @Override - public CiRegister getFrameRegister() { - return rsp; - } - - public CiCalleeSaveArea getCalleeSaveArea() { - return registerSaveArea; - } - - @Override - public String toString() { - String res = String.format( - "Allocatable: " + Arrays.toString(getAllocatableRegisters()) + "%n" + - "CallerSave: " + Arrays.toString(getCallerSaveRegisters()) + "%n" + - "CalleeSave: " + getCalleeSaveArea() + "%n" + - "Scratch: " + getScratchRegister() + "%n"); - return res; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/HotSpotRuntime.java --- a/graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/HotSpotRuntime.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,245 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.runtime; - -import java.io.*; -import java.lang.reflect.*; -import java.util.*; - -import com.sun.cri.ci.*; -import com.sun.cri.ci.CiTargetMethod.Call; -import com.sun.cri.ci.CiTargetMethod.DataPatch; -import com.sun.cri.ci.CiTargetMethod.Safepoint; -import com.sun.cri.ri.*; -import com.sun.max.asm.dis.*; -import com.sun.max.lang.*; - -/** - * CRI runtime implementation for the HotSpot VM. - */ -public class HotSpotRuntime implements RiRuntime { - - final HotSpotVMConfig config; - final HotSpotRegisterConfig regConfig; - final HotSpotRegisterConfig globalStubRegConfig; - private final Compiler compiler; - - - public HotSpotRuntime(HotSpotVMConfig config, Compiler compiler) { - this.config = config; - this.compiler = compiler; - regConfig = new HotSpotRegisterConfig(config, false); - globalStubRegConfig = new HotSpotRegisterConfig(config, true); - } - - @Override - public int codeOffset() { - return 0; - } - - @Override - public String disassemble(byte[] code, long address) { - return disassemble(code, new DisassemblyPrinter(false), address); - } - - private String disassemble(byte[] code, DisassemblyPrinter disassemblyPrinter, long address) { - final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); - final ISA instructionSet = ISA.AMD64; - Disassembler.disassemble(byteArrayOutputStream, code, instructionSet, WordWidth.BITS_64, address, null, disassemblyPrinter); - return byteArrayOutputStream.toString(); - } - - @Override - public String disassemble(final CiTargetMethod targetMethod) { - - final DisassemblyPrinter disassemblyPrinter = new DisassemblyPrinter(false) { - - private String toString(Call call) { - if (call.runtimeCall != null) { - return "{" + call.runtimeCall.name() + "}"; - } else if (call.symbol != null) { - return "{" + call.symbol + "}"; - } else if (call.globalStubID != null) { - return "{" + call.globalStubID + "}"; - } else { - return "{" + call.method + "}"; - } - } - - private String siteInfo(int pcOffset) { - for (Call call : targetMethod.directCalls) { - if (call.pcOffset == pcOffset) { - return toString(call); - } - } - for (Call call : targetMethod.indirectCalls) { - if (call.pcOffset == pcOffset) { - return toString(call); - } - } - for (Safepoint site : targetMethod.safepoints) { - if (site.pcOffset == pcOffset) { - return "{safepoint}"; - } - } - for (DataPatch site : targetMethod.dataReferences) { - if (site.pcOffset == pcOffset) { - return "{" + site.constant + "}"; - } - } - return null; - } - - @Override - protected String disassembledObjectString(Disassembler disassembler, DisassembledObject disassembledObject) { - final String string = super.disassembledObjectString(disassembler, disassembledObject); - - String site = siteInfo(disassembledObject.startPosition()); - if (site != null) { - return string + " " + site; - } - return string; - } - }; - final byte[] code = Arrays.copyOf(targetMethod.targetCode(), targetMethod.targetCodeSize()); - return disassemble(code, disassemblyPrinter, 0L); - } - - @Override - public String disassemble(RiMethod method) { - return "No disassembler available"; - } - - @Override - public RiConstantPool getConstantPool(RiMethod method) { - return ((HotSpotTypeResolved) method.holder()).constantPool(); - } - - @Override - public RiOsrFrame getOsrFrame(RiMethod method, int bci) { - return null; - } - - public Class getJavaClass(CiConstant c) { - return null; - } - - @Override - public RiType asRiType(CiKind kind) { - return compiler.getVMEntries().getType(kind.toJavaClass()); - } - - @Override - public RiType getTypeOf(CiConstant constant) { - return compiler.getVMEntries().getRiType(constant); - } - - @Override - public boolean isExceptionType(RiType type) { - return type.isSubtypeOf(compiler.getVMEntries().getType(Throwable.class)); - } - - @Override - public RiSnippets getSnippets() { - throw new UnsupportedOperationException("getSnippets"); - } - - @Override - public boolean mustInline(RiMethod method) { - return false; - } - - @Override - public boolean mustNotCompile(RiMethod method) { - return false; - } - - @Override - public boolean mustNotInline(RiMethod method) { - return Modifier.isNative(method.accessFlags()); - } - - @Override - public Object registerGlobalStub(CiTargetMethod targetMethod, String name) { - return HotSpotTargetMethod.installStub(compiler, targetMethod, name); - } - - @Override - public int sizeOfBasicObjectLock() { - // TODO shouldn't be hard coded - return 2 * 8; - } - - @Override - public int basicObjectLockOffsetInBytes() { - return 8; - } - - @Override - public CiConstant invoke(RiMethod method, CiMethodInvokeArguments args) { - return null; - } - - @Override - public CiConstant foldWordOperation(int opcode, CiMethodInvokeArguments args) { - throw new UnsupportedOperationException("foldWordOperation"); - } - - @Override - public boolean areConstantObjectsEqual(CiConstant x, CiConstant y) { - return compiler.getVMEntries().compareConstantObjects(x, y); - } - - @Override - public RiRegisterConfig getRegisterConfig(RiMethod method) { - return regConfig; - } - - /** - * HotSpots needs an area suitable for storing a program counter for temporary use during the deoptimization process. - */ - @Override - public int getCustomStackAreaSize() { - return 8; - } - - @Override - public boolean supportsArrayIntrinsics() { - return true; - } - - @Override - public int getArrayLength(CiConstant array) { - return compiler.getVMEntries().getArrayLength(array); - } - - @Override - public Class asJavaClass(CiConstant c) { - return null; - } - - @Override - public Object asJavaObject(CiConstant c) { - return null; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/HotSpotSignature.java --- a/graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/HotSpotSignature.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,149 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.runtime; - -import java.util.*; - -import com.sun.cri.ci.*; -import com.sun.cri.ri.*; - -/** - * Represents a method signature. - */ -public class HotSpotSignature extends CompilerObject implements RiSignature { - - private final List arguments = new ArrayList(); - private final String returnType; - private final String originalString; - private RiType[] argumentTypes; - private RiType returnTypeCache; - - public HotSpotSignature(Compiler compiler, String signature) { - super(compiler); - assert signature.length() > 0; - this.originalString = signature; - - if (signature.charAt(0) == '(') { - int cur = 1; - while (cur < signature.length() && signature.charAt(cur) != ')') { - int nextCur = parseSignature(signature, cur); - arguments.add(signature.substring(cur, nextCur)); - cur = nextCur; - } - - cur++; - int nextCur = parseSignature(signature, cur); - returnType = signature.substring(cur, nextCur); - assert nextCur == signature.length(); - } else { - returnType = null; - } - } - - private int parseSignature(String signature, int cur) { - char first; - do { - first = signature.charAt(cur++); - } while (first == '['); - - switch (first) { - case 'L': - while (signature.charAt(cur) != ';') { - cur++; - } - cur++; - break; - case 'V': - case 'I': - case 'B': - case 'C': - case 'D': - case 'F': - case 'J': - case 'S': - case 'Z': - break; - default: - assert false; - } - return cur; - } - - @Override - public int argumentCount(boolean withReceiver) { - return arguments.size() + (withReceiver ? 1 : 0); - } - - @Override - public CiKind argumentKindAt(int index) { - return CiKind.fromTypeString(arguments.get(index)); - } - - @Override - public int argumentSlots(boolean withReceiver) { - - int argSlots = 0; - for (int i = 0; i < argumentCount(false); i++) { - argSlots += argumentKindAt(i).sizeInSlots(); - } - - return argSlots + (withReceiver ? 1 : 0); - } - - @Override - public RiType argumentTypeAt(int index, RiType accessingClass) { - if (argumentTypes == null) { - argumentTypes = new RiType[arguments.size()]; - } - RiType type = argumentTypes[index]; - if (type == null) { - type = compiler.getVMEntries().RiSignature_lookupType(arguments.get(index), (HotSpotTypeResolved) accessingClass); - argumentTypes[index] = type; - } - return type; - } - - @Override - public String asString() { - return originalString; - } - - @Override - public CiKind returnKind() { - return CiKind.fromTypeString(returnType); - } - - @Override - public RiType returnType(RiType accessingClass) { - if (returnTypeCache == null) { - returnTypeCache = compiler.getVMEntries().RiSignature_lookupType(returnType, (HotSpotTypeResolved) accessingClass); - } - return returnTypeCache; - } - - @Override - public String toString() { - return "HotSpotSignature<" + originalString + ">"; - } - -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/HotSpotTarget.java --- a/graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/HotSpotTarget.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.runtime; - -import com.sun.cri.ci.*; - -/** - * HotSpot-specific CiTarget that provides the correct stack frame size alignment. - */ -public class HotSpotTarget extends CiTarget { - - public HotSpotTarget(CiArchitecture arch, boolean isMP, int spillSlotSize, int stackAlignment, int pageSize, int cacheAlignment, boolean inlineObjects) { - super(arch, isMP, spillSlotSize, stackAlignment, pageSize, cacheAlignment, inlineObjects, true); - } - - @Override - public int alignFrameSize(int frameSize) { - // account for the stored rbp value - return super.alignFrameSize(frameSize + wordSize) - wordSize; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/HotSpotTargetMethod.java --- a/graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/HotSpotTargetMethod.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,106 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.runtime; - -import java.util.*; - -import com.oracle.graal.runtime.logging.*; -import com.sun.cri.ci.*; -import com.sun.cri.ci.CiTargetMethod.*; - -/** - * CiTargetMethod augmented with HotSpot-specific information. - */ -public final class HotSpotTargetMethod extends CompilerObject { - - public final CiTargetMethod targetMethod; - public final HotSpotMethodResolved method; // used only for methods - public final String name; // used only for stubs - - public final Site[] sites; - public final ExceptionHandler[] exceptionHandlers; - - private HotSpotTargetMethod(Compiler compiler, HotSpotMethodResolved method, CiTargetMethod targetMethod) { - super(compiler); - this.method = method; - this.targetMethod = targetMethod; - this.name = null; - - sites = getSortedSites(targetMethod); - if (targetMethod.exceptionHandlers == null) { - exceptionHandlers = null; - } else { - exceptionHandlers = targetMethod.exceptionHandlers.toArray(new ExceptionHandler[targetMethod.exceptionHandlers.size()]); - } - } - - private HotSpotTargetMethod(Compiler compiler, CiTargetMethod targetMethod, String name) { - super(compiler); - this.method = null; - this.targetMethod = targetMethod; - this.name = name; - - sites = getSortedSites(targetMethod); - assert targetMethod.exceptionHandlers == null || targetMethod.exceptionHandlers.size() == 0; - exceptionHandlers = null; - } - - private Site[] getSortedSites(CiTargetMethod target) { - List[] lists = new List[] {target.directCalls, target.indirectCalls, target.safepoints, target.dataReferences, target.marks}; - int count = 0; - for (List list : lists) { - count += list.size(); - } - Site[] result = new Site[count]; - int pos = 0; - for (List list : lists) { - for (Object elem : list) { - result[pos++] = (Site) elem; - } - } - Arrays.sort(result, new Comparator() { - - public int compare(Site s1, Site s2) { - if (s1.pcOffset == s2.pcOffset && (s1 instanceof Mark ^ s2 instanceof Mark)) { - return s1 instanceof Mark ? -1 : 1; - } - return s1.pcOffset - s2.pcOffset; - } - }); - if (Logger.ENABLED) { - for (Site site : result) { - Logger.log(site.pcOffset + ": " + site); - } - } - return result; - } - - public static void installMethod(Compiler compiler, HotSpotMethodResolved method, CiTargetMethod targetMethod) { - compiler.getVMEntries().installMethod(new HotSpotTargetMethod(compiler, method, targetMethod)); - } - - public static Object installStub(Compiler compiler, CiTargetMethod targetMethod, String name) { - return compiler.getVMEntries().installStub(new HotSpotTargetMethod(compiler, targetMethod, name)); - } - -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/HotSpotType.java --- a/graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/HotSpotType.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.runtime; - -import com.sun.cri.ri.*; - -/** - * Common interface for all HotSpot RiType-implementations. - */ -public abstract class HotSpotType extends CompilerObject implements RiType { - protected String name; - - protected HotSpotType(Compiler compiler) { - super(compiler); - } - - @Override - public final String name() { - return name; - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/HotSpotTypePrimitive.java --- a/graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/HotSpotTypePrimitive.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,153 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.runtime; - -import com.sun.c1x.util.*; -import com.sun.cri.ci.*; -import com.sun.cri.ri.*; - -/** - * Implementation of RiType for primitive HotSpot types. - */ -public final class HotSpotTypePrimitive extends HotSpotType { - - private CiKind kind; - - - HotSpotTypePrimitive(Compiler compiler, CiKind kind) { - super(compiler); - this.kind = kind; - this.name = kind.toString(); - } - - @Override - public int accessFlags() { - return kind.toJavaClass().getModifiers(); - } - - @Override - public RiType arrayOf() { - return compiler.getVMEntries().getPrimitiveArrayType(kind); - } - - @Override - public RiType componentType() { - return null; - } - - @Override - public RiType exactType() { - return this; - } - - @Override - public RiType superType() { - return null; - } - - @Override - public CiConstant getEncoding(Representation r) { - throw Util.unimplemented("HotSpotTypePrimitive.getEncoding"); - } - - @Override - public CiKind getRepresentationKind(Representation r) { - return kind; - } - - @Override - public boolean hasFinalizableSubclass() { - return false; - } - - @Override - public boolean hasFinalizer() { - return false; - } - - @Override - public boolean hasSubclass() { - return false; - } - - @Override - public boolean isArrayClass() { - return false; - } - - @Override - public boolean isInitialized() { - return true; - } - - @Override - public boolean isInstance(CiConstant obj) { - return false; - } - - @Override - public boolean isInstanceClass() { - return false; - } - - @Override - public boolean isInterface() { - return false; - } - - @Override - public boolean isResolved() { - return true; - } - - @Override - public boolean isSubtypeOf(RiType other) { - return false; - } - - @Override - public CiKind kind() { - return kind; - } - - @Override - public RiMethod resolveMethodImpl(RiMethod method) { - return null; - } - - @Override - public String toString() { - return "HotSpotTypePrimitive<" + kind + ">"; - } - - @Override - public RiType uniqueConcreteSubtype() { - return this; - } - - @Override - public RiMethod uniqueConcreteMethod(RiMethod method) { - return null; - } - -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/HotSpotTypeResolved.java --- a/graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/HotSpotTypeResolved.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.runtime; - -import com.oracle.graal.runtime.server.*; -import com.sun.cri.ri.*; - -public interface HotSpotTypeResolved extends RiType, Remote { - - String toString(); - - RiConstantPool constantPool(); - - int instanceSize(); - - RiField createRiField(String name, RiType type, int offset, int flags); - -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/HotSpotTypeResolvedImpl.java --- a/graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/HotSpotTypeResolvedImpl.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,226 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.runtime; - -import java.lang.reflect.*; -import java.util.*; - -import com.sun.cri.ci.*; -import com.sun.cri.ri.*; - -/** - * Implementation of RiType for resolved non-primitive HotSpot classes. - */ -public final class HotSpotTypeResolvedImpl extends HotSpotType implements HotSpotTypeResolved { - - private Class javaMirror; - private String simpleName; - private int accessFlags; - private boolean hasFinalizer; - private boolean hasSubclass; - private boolean hasFinalizableSubclass; - private boolean isInitialized; - private boolean isArrayClass; - private boolean isInstanceClass; - private boolean isInterface; - private int instanceSize; - private RiType componentType; - private HashMap fieldCache; - private RiConstantPool pool; - private RiType superType; - private boolean superTypeSet; - - private HotSpotTypeResolvedImpl() { - super(null); - } - - @Override - public int accessFlags() { - return accessFlags; - } - - @Override - public RiType arrayOf() { - return compiler.getVMEntries().RiType_arrayOf(this); - } - - @Override - public RiType componentType() { - return compiler.getVMEntries().RiType_componentType(this); - } - - @Override - public RiType uniqueConcreteSubtype() { - return compiler.getVMEntries().RiType_uniqueConcreteSubtype(this); - } - - @Override - public RiType superType() { - if (!superTypeSet) { - superType = compiler.getVMEntries().RiType_superType(this); - superTypeSet = true; - } - return superType; - } - - @Override - public RiType exactType() { - if (Modifier.isFinal(accessFlags)) { - return this; - } - return null; - } - - @Override - public CiConstant getEncoding(Representation r) { - switch (r) { - case JavaClass: - return CiConstant.forObject(javaMirror); - case ObjectHub: - return CiConstant.forObject(this); - case StaticFields: - return CiConstant.forObject(javaMirror); - case TypeInfo: - return CiConstant.forObject(this); - default: - return null; - } - } - - @Override - public CiKind getRepresentationKind(Representation r) { - return CiKind.Object; - } - - @Override - public boolean hasFinalizableSubclass() { - return hasFinalizableSubclass; - } - - @Override - public boolean hasFinalizer() { - return hasFinalizer; - } - - @Override - public boolean hasSubclass() { - return hasSubclass; - } - - @Override - public boolean isArrayClass() { - return isArrayClass; - } - - @Override - public boolean isInitialized() { - return isInitialized; - } - - @Override - public boolean isInstance(CiConstant obj) { - return javaMirror.isInstance(obj); - } - - @Override - public boolean isInstanceClass() { - return isInstanceClass; - } - - @Override - public boolean isInterface() { - return isInterface; - } - - @Override - public boolean isResolved() { - return true; - } - - @Override - public boolean isSubtypeOf(RiType other) { - if (other instanceof HotSpotTypeResolved) { - return compiler.getVMEntries().RiType_isSubtypeOf(this, other); - } - // No resolved type is a subtype of an unresolved type. - return false; - } - - @Override - public CiKind kind() { - return CiKind.Object; - } - - @Override - public RiMethod resolveMethodImpl(RiMethod method) { - assert method instanceof HotSpotMethod; - return compiler.getVMEntries().RiType_resolveMethodImpl(this, method.name(), method.signature().asString()); - } - - @Override - public String toString() { - return "HotSpotType<" + simpleName + ", resolved>"; - } - - @Override - public RiConstantPool constantPool() { - // TODO: Implement constant pool without the need for VmId and cache the constant pool. - return compiler.getVMEntries().RiType_constantPool(this); - } - - @Override - public int instanceSize() { - return instanceSize; - } - - @Override - public RiField createRiField(String name, RiType type, int offset, int flags) { - RiField result = null; - - long id = offset + ((long) flags << 32); - - // (tw) Must cache the fields, because the local load elimination only works if the objects from two field lookups are equal. - if (fieldCache == null) { - fieldCache = new HashMap(8); - } else { - result = fieldCache.get(id); - } - - if (result == null) { - result = new HotSpotField(compiler, this, name, type, offset, flags); - fieldCache.put(id, result); - } else { - assert result.name().equals(name); - assert result.accessFlags() == flags; - } - - return result; - } - - @Override - public RiMethod uniqueConcreteMethod(RiMethod method) { - assert method instanceof HotSpotMethodResolved; - return ((HotSpotMethodResolved) method).uniqueConcreteMethod(); - } - -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/HotSpotTypeUnresolved.java --- a/graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/HotSpotTypeUnresolved.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,204 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.runtime; - -import com.sun.cri.ci.*; -import com.sun.cri.ri.*; - -/** - * Implementation of RiType for unresolved HotSpot classes. - */ -public class HotSpotTypeUnresolved extends HotSpotType { - - public final String simpleName; - public final int dimensions; - - /** - * Creates a new unresolved type for a specified type descriptor. - */ - public HotSpotTypeUnresolved(Compiler compiler, String name) { - super(compiler); - assert name.length() > 0 : "name cannot be empty"; - - int dimensions = 0; - // Decode name if necessary. - if (name.charAt(name.length() - 1) == ';') { - int startIndex = 0; - while (name.charAt(startIndex) == '[') { - startIndex++; - dimensions++; - } - assert name.charAt(startIndex) == 'L'; - this.simpleName = name.substring(startIndex + 1, name.length() - 1); - this.name = name; - } else { - this.simpleName = name; - this.name = getFullName(name, dimensions); - } - - this.dimensions = dimensions; - } - - public HotSpotTypeUnresolved(Compiler compiler, String name, int dimensions) { - super(compiler); - assert dimensions >= 0; - this.simpleName = name; - this.dimensions = dimensions; - this.name = getFullName(name, dimensions); - } - - private String getFullName(String name, int dimensions) { - StringBuilder str = new StringBuilder(); - for (int i = 0; i < dimensions; i++) { - str.append('['); - } - str.append('L').append(simpleName).append(';'); - return str.toString(); - } - - @Override - public RiType uniqueConcreteSubtype() { - throw unresolved("uniqueConcreteSubtype"); - } - - @Override - public boolean hasSubclass() { - throw unresolved("hasSubclass()"); - } - - @Override - public boolean hasFinalizer() { - throw unresolved("hasFinalizer()"); - } - - @Override - public boolean hasFinalizableSubclass() { - throw unresolved("hasFinalizableSubclass()"); - } - - @Override - public boolean isInterface() { - throw unresolved("isInterface()"); - } - - @Override - public boolean isArrayClass() { - return dimensions > 0; - } - - @Override - public boolean isInstanceClass() { - throw unresolved("isInstanceClass()"); - } - - @Override - public int accessFlags() { - throw unresolved("accessFlags()"); - } - - @Override - public boolean isResolved() { - return false; - } - - @Override - public boolean isInitialized() { - throw unresolved("isInitialized()"); - } - - @Override - public boolean isSubtypeOf(RiType other) { - throw unresolved("isSubtypeOf()"); - } - - @Override - public boolean isInstance(CiConstant obj) { - throw unresolved("isInstance()"); - } - - @Override - public RiType componentType() { - assert isArrayClass() : "no array class" + name(); - return new HotSpotTypeUnresolved(compiler, simpleName, dimensions - 1); - } - - @Override - public RiType exactType() { - throw unresolved("exactType()"); - } - - @Override - public RiType superType() { - throw unresolved("superType()"); - } - - @Override - public RiType arrayOf() { - return new HotSpotTypeUnresolved(compiler, simpleName, dimensions + 1); - } - - @Override - public RiMethod resolveMethodImpl(RiMethod method) { - throw unresolved("resolveMethodImpl()"); - } - - @Override - public CiKind kind() { - return CiKind.Object; - } - - private CiUnresolvedException unresolved(String operation) { - throw new CiUnresolvedException(operation + " not defined for unresolved class " + simpleName); - } - - @Override - public int hashCode() { - return simpleName.hashCode(); - } - - @Override - public boolean equals(Object o) { - return o == this; - } - - @Override - public String toString() { - return "HotSpotType<" + simpleName + ", unresolved>"; - } - - @Override - public CiConstant getEncoding(RiType.Representation r) { - throw unresolved("getEncoding()"); - } - - @Override - public CiKind getRepresentationKind(RiType.Representation r) { - return CiKind.Object; - } - - @Override - public RiMethod uniqueConcreteMethod(RiMethod method) { - throw unresolved("uniqueConcreteMethod"); - } - -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/HotSpotVMConfig.java --- a/graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/HotSpotVMConfig.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,119 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.runtime; - -import com.sun.cri.ci.*; - -/** - * Used to communicate configuration details, runtime offsets, etc. to c1x upon compileMethod. - */ -public final class HotSpotVMConfig extends CompilerObject { - - private HotSpotVMConfig() { - super(null); - } - - // os information, register layout, code generation, ... - public boolean windowsOs; - public int codeEntryAlignment; - public boolean verifyPointers; - public boolean useFastLocking; - public boolean useFastNewObjectArray; - public boolean useFastNewTypeArray; - - // offsets, ... - public int vmPageSize; - public int stackShadowPages; - public int hubOffset; - public int arrayLengthOffset; - public int klassStateOffset; - public int klassStateFullyInitialized; - public int[] arrayOffsets; - public int arrayClassElementOffset; - public int threadTlabTopOffset; - public int threadTlabEndOffset; - public int threadObjectOffset; - public int instanceHeaderPrototypeOffset; - public int threadExceptionOopOffset; - public int threadExceptionPcOffset; - public int threadMultiNewArrayStorage; - public long cardtableStartAddress; - public int cardtableShift; - public long safepointPollingAddress; - public int classMirrorOffset; - - // runtime stubs - public long debugStub; - public long instanceofStub; - public long newInstanceStub; - public long unresolvedNewInstanceStub; - public long newTypeArrayStub; - public long newObjectArrayStub; - public long newMultiArrayStub; - public long loadKlassStub; - public long accessFieldStub; - public long resolveStaticCallStub; - public long inlineCacheMissStub; - public long unwindExceptionStub; - public long handleExceptionStub; - public long handleDeoptStub; - public long monitorEnterStub; - public long monitorExitStub; - public long fastMonitorEnterStub; - public long fastMonitorExitStub; - public long verifyPointerStub; - - public void check() { - assert vmPageSize >= 16; - assert codeEntryAlignment > 0; - assert stackShadowPages > 0; - } - - public int getArrayOffset(CiKind kind) { - return arrayOffsets[getKindNumber(kind)]; - } - - private int getKindNumber(CiKind kind) { - if (kind == CiKind.Boolean) { - return 0; - } else if (kind == CiKind.Byte) { - return 1; - } else if (kind == CiKind.Short) { - return 2; - } else if (kind == CiKind.Char) { - return 3; - } else if (kind == CiKind.Int) { - return 4; - } else if (kind == CiKind.Float) { - return 5; - } else if (kind == CiKind.Long) { - return 6; - } else if (kind == CiKind.Double) { - return 7; - } else if (kind == CiKind.Object) { - return 8; - } else { - throw new RuntimeException(kind + " is not a Java kind"); - } - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/HotSpotXirGenerator.java --- a/graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/HotSpotXirGenerator.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1330 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.runtime; - -import static com.oracle.graal.runtime.TemplateFlag.*; -import static com.sun.cri.ci.CiCallingConvention.Type.*; - -import java.lang.reflect.*; -import java.util.*; -import java.util.concurrent.*; - -import com.oracle.max.asm.target.amd64.*; -import com.sun.cri.ci.*; -import com.sun.cri.ci.CiAddress.*; -import com.sun.cri.ci.CiRegister.*; -import com.sun.cri.ri.*; -import com.sun.cri.ri.RiType.*; -import com.sun.cri.xir.*; -import com.sun.cri.xir.CiXirAssembler.*; - -public class HotSpotXirGenerator implements RiXirGenerator { - - // this needs to correspond to c1x_CodeInstaller.hpp - // @formatter:off - private static final Integer MARK_VERIFIED_ENTRY = 0x0001; - private static final Integer MARK_UNVERIFIED_ENTRY = 0x0002; - private static final Integer MARK_OSR_ENTRY = 0x0003; - private static final Integer MARK_UNWIND_ENTRY = 0x0004; - private static final Integer MARK_EXCEPTION_HANDLER_ENTRY = 0x0005; - private static final Integer MARK_DEOPT_HANDLER_ENTRY = 0x0006; - - private static final Integer MARK_STATIC_CALL_STUB = 0x1000; - - private static final Integer MARK_INVOKE_INVALID = 0x2000; - private static final Integer MARK_INVOKEINTERFACE = 0x2001; - private static final Integer MARK_INVOKESTATIC = 0x2002; - private static final Integer MARK_INVOKESPECIAL = 0x2003; - private static final Integer MARK_INVOKEVIRTUAL = 0x2004; - - private static final Integer MARK_IMPLICIT_NULL = 0x3000; - - private static final Integer MARK_KLASS_PATCHING = 0x4000; - private static final Integer MARK_DUMMY_OOP_RELOCATION = 0x4001; - private static final Integer MARK_ACCESS_FIELD_PATCHING = 0x4002; - // @formatter:on - - private final HotSpotVMConfig config; - private final CiTarget target; - private final RiRegisterConfig registerConfig; - private final Compiler compiler; - - private CiXirAssembler globalAsm; - - public HotSpotXirGenerator(HotSpotVMConfig config, CiTarget target, RiRegisterConfig registerConfig, Compiler compiler) { - this.config = config; - this.target = target; - this.registerConfig = registerConfig; - this.compiler = compiler; - } - - private SimpleTemplates prologueTemplates = new SimpleTemplates(STATIC_METHOD) { - - @Override - protected XirTemplate create(CiXirAssembler asm, long flags) { - asm.restart(CiKind.Void); - XirOperand framePointer = asm.createRegisterTemp("frame pointer", CiKind.Word, AMD64.rbp); - XirOperand stackPointer = asm.createRegisterTemp("stack pointer", CiKind.Word, AMD64.rsp); - XirLabel unverifiedStub = null; - - asm.mark(MARK_OSR_ENTRY); - asm.mark(MARK_UNVERIFIED_ENTRY); - if (!is(STATIC_METHOD, flags)) { - unverifiedStub = asm.createOutOfLineLabel("unverified"); - - XirOperand temp = asm.createRegisterTemp("temp (r10)", CiKind.Word, AMD64.r10); - XirOperand cache = asm.createRegisterTemp("cache (rax)", CiKind.Word, AMD64.rax); - - CiCallingConvention conventions = registerConfig.getCallingConvention(JavaCallee, new CiKind[] {CiKind.Object}, target); - XirOperand receiver = asm.createRegisterTemp("receiver", CiKind.Word, conventions.locations[0].asRegister()); - - asm.pload(CiKind.Word, temp, receiver, asm.i(config.hubOffset), false); - asm.jneq(unverifiedStub, cache, temp); - } - asm.align(config.codeEntryAlignment); - asm.mark(MARK_VERIFIED_ENTRY); - asm.stackOverflowCheck(); - asm.push(framePointer); - asm.mov(framePointer, stackPointer); - asm.pushFrame(); - - // -- out of line ------------------------------------------------------- - XirOperand thread = asm.createRegisterTemp("thread", CiKind.Word, AMD64.r15); - XirOperand exceptionOop = asm.createTemp("exception oop", CiKind.Object); - XirLabel unwind = asm.createOutOfLineLabel("unwind"); - asm.bindOutOfLine(unwind); - - asm.mark(MARK_UNWIND_ENTRY); - - asm.pload(CiKind.Object, exceptionOop, thread, asm.i(config.threadExceptionOopOffset), false); - asm.pstore(CiKind.Object, thread, asm.i(config.threadExceptionOopOffset), asm.createConstant(CiConstant.NULL_OBJECT), false); - asm.pstore(CiKind.Long, thread, asm.i(config.threadExceptionPcOffset), asm.l(0), false); - - asm.callRuntime(config.unwindExceptionStub, null, exceptionOop); - asm.shouldNotReachHere(); - - asm.mark(MARK_EXCEPTION_HANDLER_ENTRY); - asm.callRuntime(config.handleExceptionStub, null); - asm.shouldNotReachHere(); - - asm.nop(1); - asm.mark(MARK_DEOPT_HANDLER_ENTRY); - asm.callRuntime(config.handleDeoptStub, null); - asm.shouldNotReachHere(); - - if (!is(STATIC_METHOD, flags)) { - asm.bindOutOfLine(unverifiedStub); - asm.jmpRuntime(config.inlineCacheMissStub); - } - - return asm.finishTemplate(is(STATIC_METHOD, flags) ? "static prologue" : "prologue"); - } - }; - - private SimpleTemplates epilogueTemplates = new SimpleTemplates(STATIC_METHOD, SYNCHRONIZED) { - - @Override - protected XirTemplate create(CiXirAssembler asm, long flags) { - asm.restart(CiKind.Void); - XirOperand framePointer = asm.createRegisterTemp("frame pointer", CiKind.Word, AMD64.rbp); - - asm.popFrame(); - asm.pop(framePointer); - - // TODO safepoint check - - return asm.finishTemplate("epilogue"); - } - }; - - private SimpleTemplates safepointTemplates = new SimpleTemplates() { - - @Override - protected XirTemplate create(CiXirAssembler asm, long flags) { - asm.restart(CiKind.Void); - - // XirOperand temp = asm.createRegister("temp", CiKind.Word, AMD64.rax); - // asm.pload(CiKind.Word, temp, asm.w(config.safepointPollingAddress), true); - - return asm.finishTemplate("safepoint"); - } - }; - - private SimpleTemplates exceptionObjectTemplates = new SimpleTemplates() { - - @Override - protected XirTemplate create(CiXirAssembler asm, long flags) { - XirOperand result = asm.restart(CiKind.Object); - XirOperand thread = asm.createRegisterTemp("thread", CiKind.Word, AMD64.r15); - - asm.pload(CiKind.Object, result, thread, asm.i(config.threadExceptionOopOffset), false); - asm.pstore(CiKind.Object, thread, asm.i(config.threadExceptionOopOffset), asm.o(null), false); - asm.pstore(CiKind.Long, thread, asm.i(config.threadExceptionPcOffset), asm.l(0), false); - - return asm.finishTemplate("exception object"); - } - }; - - private SimpleTemplates invokeInterfaceTemplates = new SimpleTemplates(NULL_CHECK) { - - @Override - protected XirTemplate create(CiXirAssembler asm, long flags) { - asm.restart(); - XirParameter receiver = asm.createInputParameter("receiver", CiKind.Object); - XirParameter addr = asm.createConstantInputParameter("addr", CiKind.Word); - XirOperand temp = asm.createRegisterTemp("temp", CiKind.Word, AMD64.rax); - - if (is(NULL_CHECK, flags)) { - asm.nop(1); - asm.mark(MARK_IMPLICIT_NULL); - asm.pload(CiKind.Word, temp, receiver, true); - } - asm.mark(MARK_INVOKEINTERFACE); - asm.mov(temp, asm.createConstant(CiConstant.forObject(HotSpotProxy.DUMMY_CONSTANT_OBJ))); - - return asm.finishTemplate(addr, "invokeinterface"); - } - }; - - private SimpleTemplates invokeVirtualTemplates = new SimpleTemplates(NULL_CHECK) { - - @Override - protected XirTemplate create(CiXirAssembler asm, long flags) { - asm.restart(); - XirParameter receiver = asm.createInputParameter("receiver", CiKind.Object); - XirParameter addr = asm.createConstantInputParameter("addr", CiKind.Word); - XirOperand temp = asm.createRegisterTemp("temp", CiKind.Word, AMD64.rax); - - if (is(NULL_CHECK, flags)) { - asm.nop(1); - asm.mark(MARK_IMPLICIT_NULL); - asm.pload(CiKind.Word, temp, receiver, true); - } - asm.mark(MARK_INVOKEVIRTUAL); - asm.mov(temp, asm.createConstant(CiConstant.forObject(HotSpotProxy.DUMMY_CONSTANT_OBJ))); - - return asm.finishTemplate(addr, "invokevirtual"); - } - }; - - private SimpleTemplates invokeSpecialTemplates = new SimpleTemplates(NULL_CHECK) { - - @Override - protected XirTemplate create(CiXirAssembler asm, long flags) { - asm.restart(); - XirParameter receiver = asm.createInputParameter("receiver", CiKind.Object); - XirParameter addr = asm.createConstantInputParameter("addr", CiKind.Word); - XirOperand temp = asm.createRegisterTemp("temp", CiKind.Word, AMD64.rax); - XirLabel stub = asm.createOutOfLineLabel("call stub"); - - if (is(NULL_CHECK, flags)) { - asm.nop(1); - asm.mark(MARK_IMPLICIT_NULL); - asm.pload(CiKind.Word, temp, receiver, true); - } - asm.mark(MARK_INVOKESPECIAL); - - // -- out of line ------------------------------------------------------- - asm.bindOutOfLine(stub); - XirOperand method = asm.createRegisterTemp("method", CiKind.Word, AMD64.rbx); - asm.mark(MARK_STATIC_CALL_STUB, XirMark.CALLSITE); - asm.mov(method, asm.w(0L)); - XirLabel dummy = asm.createOutOfLineLabel("dummy"); - asm.jmp(dummy); - asm.bindOutOfLine(dummy); - - return asm.finishTemplate(addr, "invokespecial"); - } - }; - - private SimpleTemplates invokeStaticTemplates = new SimpleTemplates() { - - @Override - protected XirTemplate create(CiXirAssembler asm, long flags) { - asm.restart(); - XirParameter addr = asm.createConstantInputParameter("addr", CiKind.Word); - - XirLabel stub = asm.createOutOfLineLabel("call stub"); - asm.mark(MARK_INVOKESTATIC); - - // -- out of line ------------------------------------------------------- - asm.bindOutOfLine(stub); - XirOperand method = asm.createRegisterTemp("method", CiKind.Word, AMD64.rbx); - asm.mark(MARK_STATIC_CALL_STUB, XirMark.CALLSITE); - asm.mov(method, asm.w(0L)); - XirLabel dummy = asm.createOutOfLineLabel("dummy"); - asm.jmp(dummy); - asm.bindOutOfLine(dummy); - - return asm.finishTemplate(addr, "invokestatic"); - } - }; - - private SimpleTemplates monitorEnterTemplates = new SimpleTemplates(NULL_CHECK) { - - @Override - protected XirTemplate create(CiXirAssembler asm, long flags) { - asm.restart(CiKind.Void); - XirParameter object = asm.createInputParameter("object", CiKind.Object); - XirParameter lock = asm.createInputParameter("lock", CiKind.Word); - - if (is(NULL_CHECK, flags)) { - asm.nop(1); - asm.mark(MARK_IMPLICIT_NULL); - asm.pload(CiKind.Word, asm.createTemp("temp", CiKind.Word), object, true); - } - - - // (tw) It is important to use for this runtime call the debug info AFTER the monitor enter. Otherwise the monitor object - // is not correctly garbage collected. - final boolean useInfoAfter = true; - - if (config.useFastLocking) { - useRegisters(asm, AMD64.rax, AMD64.rbx); - useRegisters(asm, getGeneralParameterRegister(0)); - useRegisters(asm, getGeneralParameterRegister(1)); - asm.callRuntime(config.fastMonitorEnterStub, null, useInfoAfter, object, lock); - } else { - asm.reserveOutgoingStack(target.wordSize * 2); - asm.pstore(CiKind.Object, asm.createRegister("rsp", CiKind.Word, AMD64.RSP.asRegister()), asm.i(target.wordSize), object, false); - asm.pstore(CiKind.Word, asm.createRegister("rsp", CiKind.Word, AMD64.RSP.asRegister()), asm.i(0), lock, false); - asm.callRuntime(config.monitorEnterStub, null, useInfoAfter); - } - - return asm.finishTemplate("monitorEnter"); - } - }; - - private CiRegister getGeneralParameterRegister(int index) { - return registerConfig.getCallingConventionRegisters(CiCallingConvention.Type.RuntimeCall, RegisterFlag.CPU)[index]; - } - - private SimpleTemplates monitorExitTemplates = new SimpleTemplates(NULL_CHECK) { - - @Override - protected XirTemplate create(CiXirAssembler asm, long flags) { - asm.restart(CiKind.Void); - XirParameter object = asm.createInputParameter("object", CiKind.Object); - XirParameter lock = asm.createInputParameter("lock", CiKind.Word); - - if (config.useFastLocking) { - useRegisters(asm, AMD64.rax, AMD64.rbx); - useRegisters(asm, getGeneralParameterRegister(0)); - useRegisters(asm, getGeneralParameterRegister(1)); - asm.callRuntime(config.fastMonitorExitStub, null, object, lock); - } else { - asm.reserveOutgoingStack(target.wordSize); - asm.pstore(CiKind.Word, asm.createRegister("rsp", CiKind.Word, AMD64.RSP.asRegister()), asm.i(0), lock, false); - asm.callRuntime(config.monitorExitStub, null); - } - - return asm.finishTemplate("monitorExit"); - } - }; - - private KindTemplates getFieldTemplates = new KindTemplates(NULL_CHECK) { - - @Override - protected XirTemplate create(CiXirAssembler asm, long flags, CiKind kind) { - XirOperand result = asm.restart(kind); - XirParameter object = asm.createInputParameter("object", CiKind.Object); - - XirParameter fieldOffset = asm.createConstantInputParameter("fieldOffset", CiKind.Int); - if (is(NULL_CHECK, flags)) { - asm.nop(1); - asm.mark(MARK_IMPLICIT_NULL); - } - asm.pload(kind, result, object, fieldOffset, is(NULL_CHECK, flags)); - return asm.finishTemplate("getfield<" + kind + ">"); - } - }; - - private KindTemplates writeBarrierTemplate = new KindTemplates() { - - @Override - protected XirTemplate create(CiXirAssembler asm, long flags, CiKind kind) { - asm.restart(CiKind.Void); - XirParameter object = asm.createInputParameter("object", CiKind.Object); - - // Need temp operand, because the write barrier destroys the object pointer. - XirOperand temp = asm.createTemp("temp", CiKind.Object); - asm.mov(temp, object); - - writeBarrier(asm, temp); - return asm.finishTemplate("writeBarrier"); - } - }; - - private KindTemplates putFieldTemplates = new KindTemplates(WRITE_BARRIER, NULL_CHECK) { - - @Override - protected XirTemplate create(CiXirAssembler asm, long flags, CiKind kind) { - asm.restart(CiKind.Void); - XirParameter object = asm.createInputParameter("object", CiKind.Object); - XirParameter value = asm.createInputParameter("value", kind); - XirParameter fieldOffset = asm.createConstantInputParameter("fieldOffset", CiKind.Int); - if (kind == CiKind.Object) { - verifyPointer(asm, value); - } - if (is(NULL_CHECK, flags)) { - asm.nop(1); - asm.mark(MARK_IMPLICIT_NULL); - } - asm.pstore(kind, object, fieldOffset, value, is(NULL_CHECK, flags)); - if (is(WRITE_BARRIER, flags) && kind == CiKind.Object) { - XirOperand temp = asm.createTemp("temp", CiKind.Word); - asm.mov(temp, object); - writeBarrier(asm, temp); - } - return asm.finishTemplate("putfield<" + kind + ">"); - } - }; - - private final IndexTemplates newInstanceTemplates = new IndexTemplates() { - - @Override - protected XirTemplate create(CiXirAssembler asm, long flags, int size) { - XirOperand result = asm.restart(CiKind.Word); - XirOperand type = asm.createInputParameter("type", CiKind.Object); - - XirOperand temp1 = asm.createRegisterTemp("temp1", CiKind.Word, AMD64.rcx); - XirOperand temp2 = asm.createRegisterTemp("temp2", CiKind.Word, AMD64.rbx); - XirOperand temp2i = asm.createRegisterTemp("temp2i", CiKind.Int, AMD64.rbx); - useRegisters(asm, AMD64.rsi); - XirLabel tlabFull = asm.createOutOfLineLabel("tlab full"); - XirLabel resume = asm.createInlineLabel("resume"); - - // check if the class is already initialized - asm.pload(CiKind.Int, temp2i, type, asm.i(config.klassStateOffset), false); - asm.jneq(tlabFull, temp2i, asm.i(config.klassStateFullyInitialized)); - - XirOperand thread = asm.createRegisterTemp("thread", CiKind.Word, AMD64.r15); - asm.pload(CiKind.Word, result, thread, asm.i(config.threadTlabTopOffset), false); - asm.add(temp1, result, asm.w(size)); - asm.pload(CiKind.Word, temp2, thread, asm.i(config.threadTlabEndOffset), false); - - asm.jgt(tlabFull, temp1, temp2); - asm.pstore(CiKind.Word, thread, asm.i(config.threadTlabTopOffset), temp1, false); - - asm.bindInline(resume); - - asm.pload(CiKind.Word, temp1, type, asm.i(config.instanceHeaderPrototypeOffset), false); - asm.pstore(CiKind.Word, result, temp1, false); - asm.pstore(CiKind.Object, result, asm.i(config.hubOffset), type, false); - - if (size > 2 * target.wordSize) { - asm.mov(temp1, asm.w(0)); - for (int offset = 2 * target.wordSize; offset < size; offset += target.wordSize) { - asm.pstore(CiKind.Word, result, asm.i(offset), temp1, false); - } - } - - // -- out of line ------------------------------------------------------- - asm.bindOutOfLine(tlabFull); - XirOperand arg = asm.createRegisterTemp("runtime call argument", CiKind.Object, AMD64.rdx); - asm.mov(arg, type); - useRegisters(asm, AMD64.rax); - asm.callRuntime(config.newInstanceStub, result); - asm.jmp(resume); - - return asm.finishTemplate("new instance"); - } - }; - - private SimpleTemplates newObjectArrayCloneTemplates = new SimpleTemplates() { - - @Override - protected XirTemplate create(CiXirAssembler asm, long flags) { - XirOperand result = asm.restart(CiKind.Object); - XirParameter lengthParam = asm.createInputParameter("length", CiKind.Int, true); - XirParameter src = asm.createInputParameter("src", CiKind.Object); - - // Set up length and hub. - XirOperand length = asm.createRegisterTemp("length", CiKind.Int, AMD64.rbx); - XirOperand hub = asm.createRegisterTemp("hub", CiKind.Object, AMD64.rdx); - asm.pload(CiKind.Object, hub, src, asm.i(config.hubOffset), false); - asm.mov(length, lengthParam); - - useRegisters(asm, AMD64.rsi, AMD64.rcx, AMD64.rdi, AMD64.rax); - asm.callRuntime(config.newObjectArrayStub, result); - return asm.finishTemplate("objectArrayClone"); - } - }; - - private SimpleTemplates newObjectArrayTemplates = new SimpleTemplates() { - - @Override - protected XirTemplate create(CiXirAssembler asm, long flags) { - emitNewTypeArray(asm, flags, CiKind.Object, config.useFastNewObjectArray, config.newObjectArrayStub); - return asm.finishTemplate("newObjectArray"); - } - }; - - private void emitNewTypeArray(CiXirAssembler asm, long flags, CiKind kind, boolean useFast, long slowPathStub) { - XirOperand result = asm.restart(CiKind.Word); - - XirParameter lengthParam = asm.createInputParameter("length", CiKind.Int, true); - - XirOperand length = asm.createRegisterTemp("length", CiKind.Int, AMD64.rbx); - XirOperand hub = asm.createRegisterTemp("hub", CiKind.Object, AMD64.rdx); - - // Registers rsi, rcx, rdi, and rax are needed by the runtime call. - // Hub needs to be on rdx, length on rbx. - XirOperand temp1 = asm.createRegisterTemp("temp1", CiKind.Word, AMD64.rcx); - XirOperand temp2 = asm.createRegisterTemp("temp2", CiKind.Word, AMD64.rax); - XirOperand temp3 = asm.createRegisterTemp("temp3", CiKind.Word, AMD64.rdi); - XirOperand size = asm.createRegisterTemp("size", CiKind.Int, AMD64.rsi); - - asm.mov(hub, asm.createConstantInputParameter("hub", CiKind.Object)); - asm.mov(length, lengthParam); - - if (useFast) { - - XirLabel slowPath = asm.createOutOfLineLabel("slowPath"); - - XirLabel done = asm.createInlineLabel("done"); - - // Check for negative array size. - // TODO: Also check for upper bound - asm.jlt(slowPath, length, asm.i(0)); - - final int aligning = target.wordSize; - final int arrayLengthOffset = target.wordSize * 2; - final int arrayElementOffset = config.getArrayOffset(kind); - - // Calculate aligned size - asm.mov(size, length); - int scale = CiUtil.log2(kind.sizeInBytes(target.wordSize)); - if (scale != 0) { - asm.shl(size, size, asm.i(scale)); - } - asm.add(size, size, asm.i(arrayElementOffset + aligning - 1)); - long mask = 0xFFFFFFFFL; - mask <<= CiUtil.log2(aligning); - asm.and(size, size, asm.i((int) mask)); - - // Try tlab allocation - XirOperand thread = asm.createRegisterTemp("thread", CiKind.Word, AMD64.r15); - asm.pload(CiKind.Word, result, thread, asm.i(config.threadTlabTopOffset), false); - asm.add(temp1, result, size); - asm.pload(CiKind.Word, temp2, thread, asm.i(config.threadTlabEndOffset), false); - asm.jgt(slowPath, temp1, temp2); - asm.pstore(CiKind.Word, thread, asm.i(config.threadTlabTopOffset), temp1, false); - - // Now the new object is in result, store mark word and klass - asm.pload(CiKind.Word, temp1, hub, asm.i(config.instanceHeaderPrototypeOffset), false); - asm.pstore(CiKind.Word, result, temp1, false); - asm.pstore(CiKind.Object, result, asm.i(config.hubOffset), hub, false); - - // Store array length - asm.pstore(CiKind.Int, result, asm.i(arrayLengthOffset), length, false); - - // Initialize with 0 - XirLabel top = asm.createInlineLabel("top"); - asm.sub(size, size, asm.i(arrayElementOffset)); - asm.shr(size, size, asm.i(Scale.Times8.log2)); - asm.jeq(done, size, asm.i(0)); - asm.xor(temp3, temp3, temp3); - asm.bindInline(top); - asm.pstore(CiKind.Word, result, size, temp3, arrayElementOffset - target.wordSize, Scale.Times8, false); - asm.decAndJumpNotZero(top, size); - - asm.bindInline(done); - - // Slow path - asm.bindOutOfLine(slowPath); - asm.callRuntime(slowPathStub, result); - asm.jmp(done); - } else { - asm.callRuntime(slowPathStub, result); - } - } - - private KindTemplates newTypeArrayTemplates = new KindTemplates() { - @Override - protected XirTemplate create(CiXirAssembler asm, long flags, CiKind kind) { - emitNewTypeArray(asm, flags, kind, config.useFastNewTypeArray, config.newTypeArrayStub); - return asm.finishTemplate("newTypeArray<" + kind.toString() + ">"); - } - }; - - private final IndexTemplates multiNewArrayTemplate = new IndexTemplates() { - - @Override - protected XirTemplate create(CiXirAssembler asm, long flags, int dimensions) { - XirOperand result = asm.restart(CiKind.Object); - - XirOperand hub = asm.createRegisterTemp("hub", CiKind.Object, AMD64.rax); - XirOperand rank = asm.createRegisterTemp("rank", CiKind.Int, AMD64.rbx); - XirOperand sizes = asm.createRegisterTemp("sizes", CiKind.Long, AMD64.rcx); - XirOperand thread = asm.createRegisterTemp("thread", CiKind.Long, AMD64.r15); - asm.add(sizes, thread, asm.l(config.threadMultiNewArrayStorage)); - for (int i = 0; i < dimensions; i++) { - XirParameter length = asm.createInputParameter("length" + i, CiKind.Int, true); - asm.pstore(CiKind.Int, sizes, asm.i(i * target.sizeInBytes(CiKind.Int)), length, false); - } - - asm.mov(hub, asm.createConstantInputParameter("hub", CiKind.Object)); - - asm.mov(rank, asm.i(dimensions)); - useRegisters(asm, AMD64.rax); - asm.callRuntime(config.newMultiArrayStub, result); - return asm.finishTemplate("multiNewArray" + dimensions); - } - }; - - private SimpleTemplates checkCastTemplates = new SimpleTemplates(NULL_CHECK) { - - @Override - protected XirTemplate create(CiXirAssembler asm, long flags) { - asm.restart(); - XirParameter object = asm.createInputParameter("object", CiKind.Object); - final XirOperand hub; - hub = asm.createConstantInputParameter("hub", CiKind.Object); - - XirOperand objHub = asm.createTemp("objHub", CiKind.Object); - - XirLabel end = asm.createInlineLabel("end"); - XirLabel slowPath = asm.createOutOfLineLabel("slow path"); - - if (is(NULL_CHECK, flags)) { - // null can be cast to anything - asm.jeq(end, object, asm.o(null)); - } - - asm.pload(CiKind.Object, objHub, object, asm.i(config.hubOffset), false); - // if we get an exact match: succeed immediately - asm.jneq(slowPath, objHub, hub); - asm.bindInline(end); - - // -- out of line ------------------------------------------------------- - asm.bindOutOfLine(slowPath); - checkSubtype(asm, objHub, objHub, hub); - asm.jneq(end, objHub, asm.o(null)); - XirOperand scratch = asm.createRegisterTemp("scratch", CiKind.Object, AMD64.r10); - asm.mov(scratch, object); - - asm.callRuntime(CiRuntimeCall.Deoptimize, null); - asm.shouldNotReachHere(); - - return asm.finishTemplate(object, "instanceof"); - } - }; - - private SimpleTemplates instanceOfTemplates = new SimpleTemplates(NULL_CHECK) { - - @Override - protected XirTemplate create(CiXirAssembler asm, long flags) { - XirOperand result = asm.restart(CiKind.Boolean); - XirParameter object = asm.createInputParameter("object", CiKind.Object); - final XirOperand hub; - hub = asm.createConstantInputParameter("hub", CiKind.Object); - - XirOperand objHub = asm.createTemp("objHub", CiKind.Object); - - XirLabel end = asm.createInlineLabel("end"); - XirLabel slowPath = asm.createOutOfLineLabel("slow path"); - - if (is(NULL_CHECK, flags)) { - // null isn't "instanceof" anything - asm.mov(result, asm.b(false)); - asm.jeq(end, object, asm.o(null)); - } - - asm.pload(CiKind.Object, objHub, object, asm.i(config.hubOffset), false); - // if we get an exact match: succeed immediately - asm.mov(result, asm.b(true)); - asm.jneq(slowPath, objHub, hub); - asm.bindInline(end); - - // -- out of line ------------------------------------------------------- - asm.bindOutOfLine(slowPath); - checkSubtype(asm, result, objHub, hub); - asm.jmp(end); - - return asm.finishTemplate("instanceof"); - } - }; - - private XirOperand genArrayLength(CiXirAssembler asm, XirOperand array, boolean implicitNullException) { - XirOperand length = asm.createTemp("length", CiKind.Int); - genArrayLength(asm, length, array, implicitNullException); - return length; - } - - private void genArrayLength(CiXirAssembler asm, XirOperand length, XirOperand array, boolean implicitNullException) { - if (implicitNullException) { - asm.nop(1); - asm.mark(MARK_IMPLICIT_NULL); - } - asm.pload(CiKind.Int, length, array, asm.i(config.arrayLengthOffset), implicitNullException); - } - - private KindTemplates arrayLoadTemplates = new KindTemplates(NULL_CHECK, READ_BARRIER, BOUNDS_CHECK, GIVEN_LENGTH) { - - @Override - protected XirTemplate create(CiXirAssembler asm, long flags, CiKind kind) { - XirOperand result = asm.restart(kind); - XirParameter array = asm.createInputParameter("array", CiKind.Object); - XirParameter index = asm.createInputParameter("index", CiKind.Int, true); - XirLabel failBoundsCheck = null; - // if the length is known the array cannot be null - boolean implicitNullException = is(NULL_CHECK, flags); - - if (is(BOUNDS_CHECK, flags)) { - // load the array length and check the index - failBoundsCheck = asm.createOutOfLineLabel("failBoundsCheck"); - XirOperand length; - if (is(GIVEN_LENGTH, flags)) { - length = asm.createInputParameter("length", CiKind.Int, true); - } else { - length = genArrayLength(asm, array, implicitNullException); - } - asm.jugteq(failBoundsCheck, index, length); - implicitNullException = false; - } - int elemSize = target.sizeInBytes(kind); - if (implicitNullException) { - asm.nop(1); - asm.mark(MARK_IMPLICIT_NULL); - } - asm.pload(kind, result, array, index, config.getArrayOffset(kind), Scale.fromInt(elemSize), implicitNullException); - if (is(BOUNDS_CHECK, flags)) { - asm.bindOutOfLine(failBoundsCheck); - asm.callRuntime(CiRuntimeCall.Deoptimize, null); - asm.shouldNotReachHere(); - } - return asm.finishTemplate("arrayload<" + kind + ">"); - } - }; - - private SimpleTemplates getClassTemplates = new SimpleTemplates() { - @Override - protected XirTemplate create(CiXirAssembler asm, long flags) { - XirOperand result = asm.restart(CiKind.Object); - XirOperand object = asm.createInputParameter("object", CiKind.Object); - if (is(NULL_CHECK, flags)) { - asm.nop(1); - } - asm.pload(CiKind.Object, result, object, asm.i(config.hubOffset), is(NULL_CHECK, flags)); - asm.pload(CiKind.Object, result, result, asm.i(config.classMirrorOffset), false); - return asm.finishTemplate("currentThread"); - } - }; - - private SimpleTemplates currentThreadTemplates = new SimpleTemplates() { - @Override - protected XirTemplate create(CiXirAssembler asm, long flags) { - XirOperand result = asm.restart(CiKind.Object); - XirOperand thread = asm.createRegisterTemp("thread", CiKind.Word, AMD64.r15); - asm.pload(CiKind.Object, result, thread, asm.i(config.threadObjectOffset), false); - return asm.finishTemplate("currentThread"); - } - }; - - @Override - public XirSnippet genCurrentThread(XirSite site) { - return new XirSnippet(currentThreadTemplates.get(site)); - } - - @Override - public XirSnippet genGetClass(XirSite site, XirArgument object) { - return new XirSnippet(getClassTemplates.get(site), object); - } - - private KindTemplates arrayCopyTemplates = new KindTemplates() { - - @Override - protected XirTemplate create(CiXirAssembler asm, long flags, CiKind kind) { - asm.restart(CiKind.Void); - XirParameter src = asm.createInputParameter("src", CiKind.Object); - XirParameter srcPos = asm.createInputParameter("srcPos", CiKind.Int, true); - XirParameter dest = asm.createInputParameter("dest", CiKind.Object); - XirParameter destPos = asm.createInputParameter("destPos", CiKind.Int, true); - XirParameter length = asm.createInputParameter("length", CiKind.Int, true); - - XirOperand tempSrc = asm.createTemp("tempSrc", CiKind.Word); - XirOperand tempDest = asm.createTemp("tempDest", CiKind.Word); - XirOperand lengthOperand = asm.createRegisterTemp("lengthOperand", CiKind.Int, AMD64.rax); - - XirOperand compHub = null; - XirOperand valueHub = null; - XirOperand temp = null; - XirLabel store = null; - XirLabel slowStoreCheck = null; - - if (is(STORE_CHECK, flags) && kind == CiKind.Object) { - valueHub = asm.createRegisterTemp("valueHub", CiKind.Word, AMD64.rdi); - compHub = asm.createRegisterTemp("compHub", CiKind.Word, AMD64.rsi); - temp = asm.createRegisterTemp("temp", CiKind.Word, AMD64.r10); - } - - // Calculate the factor for the repeat move instruction. - int elementSize = kind.sizeInBytes(target.wordSize); - int factor; - boolean wordSize; - if (elementSize >= target.wordSize) { - assert elementSize % target.wordSize == 0; - wordSize = true; - factor = elementSize / target.wordSize; - } else { - factor = elementSize; - wordSize = false; - } - - // Adjust the length if the factor is not 1. - if (factor != 1) { - asm.shl(lengthOperand, length, asm.i(CiUtil.log2(factor))); - } else { - asm.mov(lengthOperand, length); - } - - // Set the start and the end pointer. - asm.lea(tempSrc, src, srcPos, config.getArrayOffset(kind), Scale.fromInt(elementSize)); - asm.lea(tempDest, dest, destPos, config.getArrayOffset(kind), Scale.fromInt(elementSize)); - - XirLabel reverse = null; - XirLabel normal = null; - - if (is(STORE_CHECK, flags)) { - reverse = asm.createInlineLabel("reverse"); - asm.jneq(reverse, src, dest); - } - - if (!is(STORE_CHECK, flags) && !is(INPUTS_DIFFERENT, flags) && !is(INPUTS_SAME, flags)) { - normal = asm.createInlineLabel("normal"); - asm.jneq(normal, src, dest); - } - - if (!is(INPUTS_DIFFERENT, flags)) { - if (reverse == null) { - reverse = asm.createInlineLabel("reverse"); - } - asm.jlt(reverse, srcPos, destPos); - } - - if (!is(STORE_CHECK, flags) && !is(INPUTS_DIFFERENT, flags) && !is(INPUTS_SAME, flags)) { - asm.bindInline(normal); - } - - // Everything set up => repeat mov. - if (wordSize) { - asm.repmov(tempSrc, tempDest, lengthOperand); - } else { - asm.repmovb(tempSrc, tempDest, lengthOperand); - } - - if (!is(INPUTS_DIFFERENT, flags) || is(STORE_CHECK, flags)) { - - XirLabel end = asm.createInlineLabel("end"); - asm.jmp(end); - - // Implement reverse copy, because srcPos < destPos and src == dest. - asm.bindInline(reverse); - - if (is(STORE_CHECK, flags)) { - asm.pload(CiKind.Object, compHub, dest, asm.i(config.hubOffset), false); - asm.pload(CiKind.Object, compHub, compHub, asm.i(config.arrayClassElementOffset), false); - } - - CiKind copyKind = wordSize ? CiKind.Object : CiKind.Byte; - XirOperand tempValue = asm.createTemp("tempValue", copyKind); - XirLabel start = asm.createInlineLabel("start"); - asm.bindInline(start); - asm.sub(lengthOperand, lengthOperand, asm.i(1)); - asm.jlt(end, lengthOperand, asm.i(0)); - - Scale scale = wordSize ? Scale.fromInt(target.wordSize) : Scale.Times1; - asm.pload(copyKind, tempValue, tempSrc, lengthOperand, 0, scale, false); - - if (is(STORE_CHECK, flags)) { - slowStoreCheck = asm.createOutOfLineLabel("slowStoreCheck"); - store = asm.createInlineLabel("store"); - asm.jeq(store, tempValue, asm.o(null)); // first check if value is null - asm.pload(CiKind.Object, valueHub, tempValue, asm.i(config.hubOffset), false); - asm.jneq(slowStoreCheck, compHub, valueHub); // then check component hub matches value hub - asm.bindInline(store); - } - - asm.pstore(copyKind, tempDest, lengthOperand, tempValue, 0, scale, false); - - asm.jmp(start); - asm.bindInline(end); - } - - if (kind == CiKind.Object) { - // Do write barriers - asm.lea(tempDest, dest, destPos, config.getArrayOffset(kind), Scale.fromInt(elementSize)); - asm.shr(tempDest, tempDest, asm.i(config.cardtableShift)); - asm.pstore(CiKind.Boolean, asm.w(config.cardtableStartAddress), tempDest, asm.b(false), false); - - XirOperand tempDestEnd = tempSrc; // Reuse src temp - asm.lea(tempDestEnd, dest, destPos, config.getArrayOffset(kind), Scale.fromInt(elementSize)); - asm.add(tempDestEnd, tempDestEnd, length); - asm.shr(tempDestEnd, tempDestEnd, asm.i(config.cardtableShift)); - - // Jump to out-of-line write barrier loop if the array is big. - XirLabel writeBarrierLoop = asm.createOutOfLineLabel("writeBarrierLoop"); - asm.jneq(writeBarrierLoop, tempDest, tempSrc); - XirLabel back = asm.createInlineLabel("back"); - asm.bindInline(back); - - asm.bindOutOfLine(writeBarrierLoop); - asm.pstore(CiKind.Boolean, asm.w(config.cardtableStartAddress), tempDestEnd, asm.b(false), false); - asm.sub(tempDestEnd, tempDestEnd, asm.i(1)); - asm.jneq(writeBarrierLoop, tempDestEnd, tempDest); - asm.jmp(back); - } - - if (is(STORE_CHECK, flags)) { - assert kind == CiKind.Object; - useRegisters(asm, AMD64.rax); - asm.bindOutOfLine(slowStoreCheck); - checkSubtype(asm, temp, valueHub, compHub); - asm.jneq(store, temp, asm.w(0)); - XirOperand scratch = asm.createRegisterTemp("scratch", CiKind.Object, AMD64.r10); - asm.mov(scratch, valueHub); - asm.callRuntime(CiRuntimeCall.Deoptimize, null); - asm.jmp(store); - } - - return asm.finishTemplate("arraycopy<" + kind + ">"); - } - }; - - private KindTemplates arrayStoreTemplates = new KindTemplates(NULL_CHECK, WRITE_BARRIER, BOUNDS_CHECK, STORE_CHECK, GIVEN_LENGTH) { - - @Override - protected XirTemplate create(CiXirAssembler asm, long flags, CiKind kind) { - asm.restart(CiKind.Void); - XirParameter array = asm.createInputParameter("array", CiKind.Object); - XirParameter index = asm.createInputParameter("index", CiKind.Int, true); - XirParameter value = asm.createInputParameter("value", kind, kind != CiKind.Object); - XirOperand temp = asm.createTemp("temp", CiKind.Word); - XirOperand valueHub = null; - XirOperand compHub = null; - XirLabel store = asm.createInlineLabel("store"); - XirLabel failBoundsCheck = null; - XirLabel slowStoreCheck = null; - // if the length is known the array cannot be null - boolean implicitNullException = is(NULL_CHECK, flags); - - if (is(BOUNDS_CHECK, flags)) { - // load the array length and check the index - failBoundsCheck = asm.createOutOfLineLabel("failBoundsCheck"); - XirOperand length; - if (is(GIVEN_LENGTH, flags)) { - length = asm.createInputParameter("length", CiKind.Int); - } else { - length = asm.createTemp("length", CiKind.Int); - if (implicitNullException) { - asm.nop(1); - asm.mark(MARK_IMPLICIT_NULL); - } - asm.pload(CiKind.Int, length, array, asm.i(config.arrayLengthOffset), implicitNullException); - implicitNullException = false; - } - asm.jugteq(failBoundsCheck, index, length); - - } - if (is(STORE_CHECK, flags) && kind == CiKind.Object) { - slowStoreCheck = asm.createOutOfLineLabel("slowStoreCheck"); - asm.jeq(store, value, asm.o(null)); // first check if value is null - valueHub = asm.createTemp("valueHub", CiKind.Object); - compHub = asm.createTemp("compHub", CiKind.Object); - if (implicitNullException) { - asm.nop(1); - asm.mark(MARK_IMPLICIT_NULL); - } - asm.pload(CiKind.Object, compHub, array, asm.i(config.hubOffset), implicitNullException); - asm.pload(CiKind.Object, compHub, compHub, asm.i(config.arrayClassElementOffset), false); - asm.pload(CiKind.Object, valueHub, value, asm.i(config.hubOffset), false); - asm.jneq(slowStoreCheck, compHub, valueHub); // then check component hub matches value hub - - implicitNullException = false; - } - asm.bindInline(store); - int elemSize = target.sizeInBytes(kind); - - if (implicitNullException) { - asm.nop(1); - asm.mark(MARK_IMPLICIT_NULL); - } - int disp = config.getArrayOffset(kind); - Scale scale = Scale.fromInt(elemSize); - if (kind == CiKind.Object) { - verifyPointer(asm, value); - } - if (is(WRITE_BARRIER, flags) && kind == CiKind.Object) { - asm.lea(temp, array, index, disp, scale); - asm.pstore(kind, temp, value, implicitNullException); - writeBarrier(asm, temp); - } else { - asm.pstore(kind, array, index, value, disp, scale, implicitNullException); - } - - // -- out of line ------------------------------------------------------- - if (is(BOUNDS_CHECK, flags)) { - asm.bindOutOfLine(failBoundsCheck); - asm.callRuntime(CiRuntimeCall.Deoptimize, null); - asm.shouldNotReachHere(); - } - if (is(STORE_CHECK, flags) && kind == CiKind.Object) { - useRegisters(asm, AMD64.rax); - asm.bindOutOfLine(slowStoreCheck); - checkSubtype(asm, temp, valueHub, compHub); - asm.jneq(store, temp, asm.w(0)); - XirOperand scratch = asm.createRegisterTemp("scratch", CiKind.Object, AMD64.r10); - asm.mov(scratch, valueHub); - asm.callRuntime(CiRuntimeCall.Deoptimize, null); - asm.shouldNotReachHere(); - } - return asm.finishTemplate("arraystore<" + kind + ">"); - } - }; - - private SimpleTemplates arrayLengthTemplates = new SimpleTemplates(NULL_CHECK) { - - @Override - protected XirTemplate create(CiXirAssembler asm, long flags) { - XirOperand result = asm.restart(CiKind.Int); - XirParameter object = asm.createInputParameter("object", CiKind.Object); - if (is(NULL_CHECK, flags)) { - asm.nop(1); - asm.mark(MARK_IMPLICIT_NULL); - } - verifyPointer(asm, object); - asm.pload(CiKind.Int, result, object, asm.i(config.arrayLengthOffset), true); - return asm.finishTemplate("arrayLength"); - } - }; - - @Override - public XirSnippet genPrologue(XirSite site, RiMethod method) { - boolean staticMethod = Modifier.isStatic(method.accessFlags()); - return new XirSnippet(staticMethod ? prologueTemplates.get(site, STATIC_METHOD) : prologueTemplates.get(site)); - } - - @Override - public XirSnippet genEpilogue(XirSite site, RiMethod method) { - return new XirSnippet(epilogueTemplates.get(site)); - } - - @Override - public XirSnippet genSafepoint(XirSite site) { - return new XirSnippet(safepointTemplates.get(site)); - } - - @Override - public XirSnippet genExceptionObject(XirSite site) { - return new XirSnippet(exceptionObjectTemplates.get(site)); - } - - @Override - public XirSnippet genResolveClass(XirSite site, RiType type, Representation rep) { - throw new CiBailout("Xir ResolveClass not available"); - } - - @Override - public XirSnippet genIntrinsic(XirSite site, XirArgument[] arguments, RiMethod method) { - return null; - } - - @Override - public XirSnippet genInvokeInterface(XirSite site, XirArgument receiver, RiMethod method) { - return new XirSnippet(invokeInterfaceTemplates.get(site), receiver, XirArgument.forWord(0)); - } - - @Override - public XirSnippet genInvokeVirtual(XirSite site, XirArgument receiver, RiMethod method) { - return new XirSnippet(invokeVirtualTemplates.get(site), receiver, XirArgument.forWord(0)); - } - - @Override - public XirSnippet genInvokeSpecial(XirSite site, XirArgument receiver, RiMethod method) { - return new XirSnippet(invokeSpecialTemplates.get(site), receiver, XirArgument.forWord(0)); - } - - @Override - public XirSnippet genInvokeStatic(XirSite site, RiMethod method) { - return new XirSnippet(invokeStaticTemplates.get(site), XirArgument.forWord(0)); - } - - @Override - public XirSnippet genMonitorEnter(XirSite site, XirArgument receiver, XirArgument lockAddress) { - return new XirSnippet(monitorEnterTemplates.get(site), receiver, lockAddress); - } - - @Override - public XirSnippet genMonitorExit(XirSite site, XirArgument receiver, XirArgument lockAddress) { - return new XirSnippet(monitorExitTemplates.get(site), receiver, lockAddress); - } - - @Override - public XirSnippet genGetField(XirSite site, XirArgument object, RiField field) { - assert field.isResolved(); - return new XirSnippet(getFieldTemplates.get(site, field.kind()), object, XirArgument.forInt(((HotSpotField) field).offset())); - } - - @Override - public XirSnippet genWriteBarrier(XirArgument object) { - return new XirSnippet(writeBarrierTemplate.get(null, CiKind.Void), object); - } - - @Override - public XirSnippet genPutField(XirSite site, XirArgument object, RiField field, XirArgument value) { - assert field.isResolved(); - return new XirSnippet(putFieldTemplates.get(site, field.kind()), object, value, XirArgument.forInt(((HotSpotField) field).offset())); - } - - @Override - public XirSnippet genGetStatic(XirSite site, XirArgument object, RiField field) { - assert field.isResolved(); - return new XirSnippet(getFieldTemplates.get(site, field.kind()), object, XirArgument.forInt(((HotSpotField) field).offset())); - } - - @Override - public XirSnippet genPutStatic(XirSite site, XirArgument object, RiField field, XirArgument value) { - assert field.isResolved(); - return new XirSnippet(putFieldTemplates.get(site, field.kind()), object, value, XirArgument.forInt(((HotSpotField) field).offset())); - } - - @Override - public XirSnippet genNewInstance(XirSite site, RiType type) { - assert type.isResolved(); - int instanceSize = ((HotSpotTypeResolved) type).instanceSize(); - return new XirSnippet(newInstanceTemplates.get(site, instanceSize), XirArgument.forObject(type)); - } - - @Override - public XirSnippet genNewArray(XirSite site, XirArgument length, CiKind elementKind, RiType componentType, RiType arrayType) { - if (elementKind == CiKind.Object) { - assert arrayType.isResolved(); - return new XirSnippet(newObjectArrayTemplates.get(site), length, XirArgument.forObject(arrayType)); - } - assert arrayType == null; - arrayType = compiler.getVMEntries().getPrimitiveArrayType(elementKind); - return new XirSnippet(newTypeArrayTemplates.get(site, elementKind), length, XirArgument.forObject(arrayType)); - } - - @Override - public XirSnippet genNewObjectArrayClone(XirSite site, XirArgument newLength, XirArgument referenceArray) { - return new XirSnippet(newObjectArrayCloneTemplates.get(site), newLength, referenceArray); - } - - @Override - public XirSnippet genNewMultiArray(XirSite site, XirArgument[] lengths, RiType type) { - assert type.isResolved(); - XirArgument[] params = Arrays.copyOf(lengths, lengths.length + 1); - params[lengths.length] = XirArgument.forObject(type); - return new XirSnippet(multiNewArrayTemplate.get(site, lengths.length), params); - } - - @Override - public XirSnippet genCheckCast(XirSite site, XirArgument receiver, XirArgument hub, RiType type) { - assert type.isResolved(); - return new XirSnippet(checkCastTemplates.get(site), receiver, hub); - } - - @Override - public XirSnippet genInstanceOf(XirSite site, XirArgument object, XirArgument hub, RiType type) { - assert type.isResolved(); - return new XirSnippet(instanceOfTemplates.get(site), object, hub); - } - - @Override - public XirSnippet genArrayLoad(XirSite site, XirArgument array, XirArgument index, XirArgument length, CiKind elementKind, RiType elementType) { - if (length == null || !site.requiresBoundsCheck()) { - return new XirSnippet(arrayLoadTemplates.get(site, elementKind), array, index); - } - return new XirSnippet(arrayLoadTemplates.get(site, elementKind, GIVEN_LENGTH), array, index, length); - } - - @Override - public XirSnippet genArrayStore(XirSite site, XirArgument array, XirArgument index, XirArgument length, XirArgument value, CiKind elementKind, RiType elementType) { - if (length == null || !site.requiresBoundsCheck()) { - return new XirSnippet(arrayStoreTemplates.get(site, elementKind), array, index, value); - } - return new XirSnippet(arrayStoreTemplates.get(site, elementKind, GIVEN_LENGTH), array, index, value, length); - } - - @Override - public XirSnippet genArrayCopy(XirSite site, XirArgument src, XirArgument srcPos, XirArgument dest, XirArgument destPos, XirArgument length, RiType elementType, boolean inputsSame, boolean inputsDifferent) { - if (elementType == null) { - return null; - } - assert !inputsDifferent || !inputsSame; - XirTemplate template = null; - if (inputsDifferent) { - template = arrayCopyTemplates.get(site, elementType.kind(), INPUTS_DIFFERENT); - } else if (inputsSame) { - template = arrayCopyTemplates.get(site, elementType.kind(), INPUTS_SAME); - } else { - template = arrayCopyTemplates.get(site, elementType.kind()); - } - return new XirSnippet(template, src, srcPos, dest, destPos, length); - } - - @Override - public XirSnippet genArrayLength(XirSite site, XirArgument array) { - return new XirSnippet(arrayLengthTemplates.get(site), array); - } - - @Override - public List buildTemplates(CiXirAssembler asm) { - this.globalAsm = asm; - List templates = new ArrayList(); - return templates; - } - - private void verifyPointer(CiXirAssembler asm, XirOperand pointer) { - if (config.verifyPointers) { - // The verify pointer stub wants the argument in a fixed register. - XirOperand fixed = asm.createRegisterTemp("fixed", CiKind.Object, AMD64.r13); - asm.push(fixed); - asm.mov(fixed, pointer); - asm.callRuntime(config.verifyPointerStub, null); - asm.pop(fixed); - } - } - - private void checkSubtype(CiXirAssembler asm, XirOperand result, XirOperand objHub, XirOperand hub) { - asm.push(objHub); - asm.push(hub); - asm.callRuntime(config.instanceofStub, null); - asm.pop(result); - asm.pop(result); - } - - private void useRegisters(CiXirAssembler asm, CiRegister... registers) { - if (registers != null) { - for (CiRegister register : registers) { - asm.createRegisterTemp("reg", CiKind.Illegal, register); - } - } - } - - private void writeBarrier(CiXirAssembler asm, XirOperand base) { - asm.shr(base, base, asm.i(config.cardtableShift)); - asm.pstore(CiKind.Boolean, asm.w(config.cardtableStartAddress), base, asm.b(false), false); - } - - public boolean is(TemplateFlag check, long flags) { - return (flags & check.bits()) == check.bits(); - } - - /** - * Base class for all the ondemand template generators. It is not normally subclassed directly, but through one of - * its subclasses (SimpleTemplates, KindTemplates, IndexTemplates). - * - * @author Lukas Stadler - */ - private abstract class Templates { - - private ConcurrentHashMap templates = new ConcurrentHashMap(); - private final long mask; - - /** - * Each flag passed to this method will cause templates with and without it to be generated. - */ - public Templates(TemplateFlag... flags) { - this.mask = getBits((int) INDEX_MASK, null, flags); - } - - protected abstract XirTemplate create(CiXirAssembler asm, long flags); - - protected long getBits(int index, XirSite site, TemplateFlag... flags) { - long bits = index; - if (site != null) { - bits |= site.requiresNullCheck() ? NULL_CHECK.bits() : 0; - bits |= site.requiresReadBarrier() ? READ_BARRIER.bits() : 0; - bits |= site.requiresWriteBarrier() ? WRITE_BARRIER.bits() : 0; - bits |= site.requiresArrayStoreCheck() ? STORE_CHECK.bits() : 0; - bits |= site.requiresBoundsCheck() ? BOUNDS_CHECK.bits() : 0; - } - if (flags != null) { - for (TemplateFlag flag : flags) { - bits |= flag.bits(); - } - } - return bits; - } - - protected XirTemplate getInternal(long flags) { - flags = flags & mask; - XirTemplate template = templates.get(flags); - if (template == null) { - template = create(HotSpotXirGenerator.this.globalAsm.copy(), flags); - templates.put(flags, template); - } - return template; - } - } - - private abstract class SimpleTemplates extends Templates { - - public SimpleTemplates(TemplateFlag... flags) { - super(flags); - } - - public XirTemplate get(XirSite site, TemplateFlag... flags) { - return getInternal(getBits(0, site, flags)); - } - } - - private abstract class IndexTemplates extends Templates { - - public IndexTemplates(TemplateFlag... flags) { - super(flags); - } - - @Override - protected final XirTemplate create(CiXirAssembler asm, long flags) { - return create(asm, flags & FLAGS_MASK, (int) (flags & INDEX_MASK)); - } - - protected abstract XirTemplate create(CiXirAssembler asm, long flags, int index); - - public XirTemplate get(XirSite site, int size, TemplateFlag... flags) { - return getInternal(getBits(size, site, flags)); - } - } - - private abstract class KindTemplates extends Templates { - - public KindTemplates(TemplateFlag... flags) { - super(flags); - } - - @Override - protected final XirTemplate create(CiXirAssembler asm, long flags) { - return create(asm, flags & FLAGS_MASK, CiKind.VALUES[(int) (flags & INDEX_MASK)]); - } - - protected abstract XirTemplate create(CiXirAssembler asm, long flags, CiKind kind); - - public XirTemplate get(XirSite site, CiKind kind, TemplateFlag... flags) { - return getInternal(getBits(kind.ordinal(), site, flags)); - } - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/InvocationSocket.java --- a/graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/InvocationSocket.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,276 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.runtime; - -import java.io.*; -import java.lang.reflect.*; -import java.util.*; - -import com.oracle.graal.runtime.logging.*; - -/** - * A collection of java.lang.reflect proxies that communicate over a socket connection. - * - * Calling a method sends the method name and the parameters through the socket. Afterwards this class waits for a - * result. While waiting for a result three types of objects can arrive through the socket: a method invocation, a - * method result or an exception. Method invocation can thus be recursive. - */ -public class InvocationSocket { - - private static final boolean DEBUG = false; - private static final boolean COUNT_CALLS = false; - - private static final HashSet cachedMethodNames = new HashSet(); - private static final HashSet forbiddenMethodNames = new HashSet(); - - static { - cachedMethodNames.add("name"); - cachedMethodNames.add("kind"); - cachedMethodNames.add("isResolved"); - cachedMethodNames.add("getVMEntries"); - cachedMethodNames.add("exactType"); - cachedMethodNames.add("isInitialized"); - forbiddenMethodNames.add("javaClass"); - } - - private final ObjectOutputStream output; - private final ObjectInputStream input; - - private final Map counts = new HashMap(); - - public InvocationSocket(ObjectOutputStream output, ObjectInputStream input) { - this.output = output; - this.input = input; - - if (COUNT_CALLS) { - Runtime.getRuntime().addShutdownHook(new Thread() { - @Override - public void run() { - SortedMap sorted = new TreeMap(); - for (Map.Entry entry : counts.entrySet()) { - sorted.put(entry.getValue(), entry.getKey()); - } - for (Map.Entry entry : sorted.entrySet()) { - System.out.println(entry.getKey() + ": " + entry.getValue()); - } - } - }); - } - } - - /** - * Represents one invocation of a method that is transferred via the socket connection. - * - * @author Lukas Stadler - */ - private static class Invocation implements Serializable { - - public Object receiver; - public String methodName; - public Object[] args; - - public Invocation(Object receiver, String methodName, Object[] args) { - this.receiver = receiver; - this.methodName = methodName; - this.args = args; - } - } - - /** - * Represents the result of an invocation that is transferred via the socket connection. - * - * @author Lukas Stadler - */ - private static class Result implements Serializable { - - public Object result; - - public Result(Object result) { - this.result = result; - } - } - - private void incCount(String name, Object[] args) { - if (COUNT_CALLS) { - name = name + (args == null ? 0 : args.length); - if (counts.get(name) != null) { - counts.put(name, counts.get(name) + 1); - } else { - counts.put(name, 1); - } - } - } - - /** - * Each instance of this class handles remote invocations for one instance of a Remote class. It will forward all - * interface methods to the other end of the socket and cache the results of calls to certain methods. - * - * @author Lukas Stadler - */ - public class Handler implements InvocationHandler { - - private final Object receiver; - private final HashMap cache = new HashMap(); - - public Handler(Object receiver) { - this.receiver = receiver; - } - - @Override - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - // only interface methods can be transferred, java.lang.Object methods - if (method.getDeclaringClass() == Object.class) { - return method.invoke(receiver, args); - } - String methodName = method.getName(); - // check if the result of this zero-arg method was cached - if (args == null || args.length == 0) { - if (cache.containsKey(methodName)) { - return cache.get(methodName); - } - } - if (forbiddenMethodNames.contains(methodName)) { - throw new IllegalAccessException(methodName + " not allowed"); - } - Object result = null; - try { - if (DEBUG) { - Logger.startScope("invoking remote " + methodName); - } - incCount(methodName, args); - - output.writeObject(new Invocation(receiver, methodName, args)); - output.flush(); - result = waitForResult(false); - - // result caching for selected methods - if ((args == null || args.length == 0) && cachedMethodNames.contains(methodName)) { - cache.put(methodName, result); - } - return result; - } catch (Throwable t) { - t.printStackTrace(); - throw t; - } finally { - if (DEBUG) { - Logger.endScope(" = " + result); - } - } - } - } - - /** - * Waits for the result of a remote method invocation. Invocations that should be executed in this VM might arrive - * while waiting for the result, and these invocations will be executed before again waiting fort he result. - */ - public Object waitForResult(boolean eofExpected) throws IOException, ClassNotFoundException { - while (true) { - Object in; - try { - in = input.readObject(); - } catch (EOFException e) { - if (eofExpected) { - return null; - } - throw e; - } - if (in instanceof Result) { - return ((Result) in).result; - } else if (in instanceof RuntimeException) { - throw (RuntimeException) in; - } else if (in instanceof Throwable) { - throw new RuntimeException((Throwable) in); - } - - Invocation invoke = (Invocation) in; - Method method = null; - for (Class clazz = invoke.receiver.getClass(); clazz != null; clazz = clazz.getSuperclass()) { - for (Method m : clazz.getDeclaredMethods()) { - if (invoke.methodName.equals(m.getName())) { - method = m; - break; - } - } - } - if (method == null) { - Exception e = new UnsupportedOperationException("unknown method " + invoke.methodName); - e.printStackTrace(); - output.writeObject(e); - output.flush(); - } else { - Object result = null; - try { - if (invoke.args == null) { - if (DEBUG) { - Logger.startScope("invoking local " + invoke.methodName); - } - result = method.invoke(invoke.receiver); - } else { - if (Logger.ENABLED && DEBUG) { - StringBuilder str = new StringBuilder(); - str.append("invoking local " + invoke.methodName + "("); - for (int i = 0; i < invoke.args.length; i++) { - str.append(i == 0 ? "" : ", "); - str.append(Logger.pretty(invoke.args[i])); - } - str.append(")"); - Logger.startScope(str.toString()); - } - result = method.invoke(invoke.receiver, invoke.args); - } - result = new Result(result); - } catch (IllegalArgumentException e) { - System.out.println("error while invoking " + invoke.methodName); - e.getCause().printStackTrace(); - result = e.getCause(); - } catch (InvocationTargetException e) { - System.out.println("error while invoking " + invoke.methodName); - e.getCause().printStackTrace(); - result = e.getCause(); - } catch (IllegalAccessException e) { - System.out.println("error while invoking " + invoke.methodName); - e.getCause().printStackTrace(); - result = e.getCause(); - } finally { - if (DEBUG) { - if (result instanceof Result) { - Logger.endScope(" = " + ((Result) result).result); - } else { - Logger.endScope(" = " + result); - } - } - } - output.writeObject(result); - output.flush(); - } - } - } - - /** - * Sends a result without invoking a method, used by CompilationServer startup code. - */ - public void sendResult(Object obj) throws IOException { - output.writeObject(new Result(obj)); - output.flush(); - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/TemplateFlag.java --- a/graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/TemplateFlag.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.runtime; - -enum TemplateFlag { - NULL_CHECK, READ_BARRIER, WRITE_BARRIER, STORE_CHECK, BOUNDS_CHECK, GIVEN_LENGTH, INPUTS_DIFFERENT, INPUTS_SAME, STATIC_METHOD, SYNCHRONIZED; - - private static final long FIRST_FLAG = 0x0000000100000000L; - public static final long FLAGS_MASK = 0x0000FFFF00000000L; - public static final long INDEX_MASK = 0x00000000FFFFFFFFL; - - public long bits() { - assert ((FIRST_FLAG << ordinal()) & FLAGS_MASK) != 0; - return FIRST_FLAG << ordinal(); - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/VMEntries.java --- a/graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/VMEntries.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,99 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.oracle.graal.runtime; - -import com.sun.cri.ci.*; -import com.sun.cri.ri.*; - -/** - * Entries into the HotSpot VM from Java code. - */ -public interface VMEntries { - - // Checkstyle: stop - - byte[] RiMethod_code(long vmId); - - int RiMethod_maxStackSize(long vmId); - - int RiMethod_maxLocals(long vmId); - - RiType RiMethod_holder(long vmId); - - String RiMethod_signature(long vmId); - - int RiMethod_accessFlags(long vmId); - - RiType RiSignature_lookupType(String returnType, HotSpotTypeResolved accessingClass); - - Object RiConstantPool_lookupConstant(long vmId, int cpi); - - RiMethod RiConstantPool_lookupMethod(long vmId, int cpi, byte byteCode); - - RiSignature RiConstantPool_lookupSignature(long vmId, int cpi); - - RiType RiConstantPool_lookupType(long vmId, int cpi); - - RiField RiConstantPool_lookupField(long vmId, int cpi, byte byteCode); - - RiConstantPool RiType_constantPool(HotSpotTypeResolved klass); - - void installMethod(HotSpotTargetMethod targetMethod); - - long installStub(HotSpotTargetMethod targetMethod); - - HotSpotVMConfig getConfiguration(); - - RiExceptionHandler[] RiMethod_exceptionHandlers(long vmId); - - RiMethod RiType_resolveMethodImpl(HotSpotTypeResolved klass, String name, String signature); - - boolean RiType_isSubtypeOf(HotSpotTypeResolved klass, RiType other); - - RiType getPrimitiveArrayType(CiKind kind); - - RiType RiType_arrayOf(HotSpotTypeResolved klass); - - RiType RiType_componentType(HotSpotTypeResolved klass); - - RiType getType(Class javaClass); - - boolean RiMethod_hasBalancedMonitors(long vmId); - - RiMethod RiMethod_uniqueConcreteMethod(long vmId); - - void recordBailout(String reason); - - RiType RiType_uniqueConcreteSubtype(HotSpotTypeResolved hotSpotTypeResolved); - - RiType RiType_superType(HotSpotTypeResolved hotSpotTypeResolved); - - int getArrayLength(CiConstant array); - - boolean compareConstantObjects(CiConstant x, CiConstant y); - - RiType getRiType(CiConstant constant); - - // Checkstyle: resume -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/VMEntriesNative.java --- a/graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/VMEntriesNative.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,142 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.oracle.graal.runtime; - -import java.lang.reflect.*; - -import com.oracle.graal.runtime.server.*; -import com.sun.cri.ci.*; -import com.sun.cri.ri.*; - -/** - * Entries into the HotSpot VM from Java code. - */ -public class VMEntriesNative implements VMEntries, Remote { - - // Checkstyle: stop - @Override - public native byte[] RiMethod_code(long vmId); - - @Override - public native int RiMethod_maxStackSize(long vmId); - - @Override - public native int RiMethod_maxLocals(long vmId); - - @Override - public native RiType RiMethod_holder(long vmId); - - @Override - public native String RiMethod_signature(long vmId); - - @Override - public native int RiMethod_accessFlags(long vmId); - - @Override - public native RiType RiSignature_lookupType(String returnType, HotSpotTypeResolved accessingClass); - - @Override - public native Object RiConstantPool_lookupConstant(long vmId, int cpi); - - @Override - public native RiMethod RiConstantPool_lookupMethod(long vmId, int cpi, byte byteCode); - - @Override - public native RiSignature RiConstantPool_lookupSignature(long vmId, int cpi); - - @Override - public native RiType RiConstantPool_lookupType(long vmId, int cpi); - - @Override - public native RiField RiConstantPool_lookupField(long vmId, int cpi, byte byteCode); - - @Override - public native RiConstantPool RiType_constantPool(HotSpotTypeResolved klass); - - @Override - public native void installMethod(HotSpotTargetMethod targetMethod); - - @Override - public native long installStub(HotSpotTargetMethod targetMethod); - - @Override - public native HotSpotVMConfig getConfiguration(); - - @Override - public native RiExceptionHandler[] RiMethod_exceptionHandlers(long vmId); - - @Override - public native RiMethod RiType_resolveMethodImpl(HotSpotTypeResolved klass, String name, String signature); - - @Override - public native boolean RiType_isSubtypeOf(HotSpotTypeResolved klass, RiType other); - - @Override - public native RiType getPrimitiveArrayType(CiKind kind); - - @Override - public native RiType RiType_arrayOf(HotSpotTypeResolved klass); - - @Override - public native RiType RiType_componentType(HotSpotTypeResolved klass); - - @Override - public native RiType RiType_uniqueConcreteSubtype(HotSpotTypeResolved klass); - - @Override - public native RiType RiType_superType(HotSpotTypeResolved klass); - - @Override - public native RiType getType(Class javaClass); - - @Override - public native boolean RiMethod_hasBalancedMonitors(long vmId); - - @Override - public native void recordBailout(String reason); - - @Override - public native RiMethod RiMethod_uniqueConcreteMethod(long vmId); - - @Override - public int getArrayLength(CiConstant array) { - return Array.getLength(array.asObject()); - } - - @Override - public boolean compareConstantObjects(CiConstant x, CiConstant y) { - return x.asObject() == y.asObject(); - } - - @Override - public RiType getRiType(CiConstant constant) { - Object o = constant.asObject(); - if (o == null) { - return null; - } - return getType(o.getClass()); - } - - // Checkstyle: resume -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/VMExits.java --- a/graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/VMExits.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.oracle.graal.runtime; - -import com.sun.cri.ci.*; -import com.sun.cri.ri.*; - -/** - * Exits from the HotSpot VM into Java code. - */ -public interface VMExits { - - void compileMethod(long methodVmId, String name, int entryBCI) throws Throwable; - - RiMethod createRiMethodResolved(long vmId, String name); - - RiMethod createRiMethodUnresolved(String name, String signature, RiType holder); - - RiSignature createRiSignature(String signature); - - RiField createRiField(RiType holder, String name, RiType type, int offset, int flags); - - RiType createRiType(long vmId, String name); - - RiType createRiTypePrimitive(int basicType); - - RiType createRiTypeUnresolved(String name); - - RiConstantPool createRiConstantPool(long vmId); - - CiConstant createCiConstant(CiKind kind, long value); - - CiConstant createCiConstantFloat(float value); - - CiConstant createCiConstantDouble(double value); - - CiConstant createCiConstantObject(Object object); - -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/VMExitsNative.java --- a/graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/VMExitsNative.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,218 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.oracle.graal.runtime; - -import java.io.*; -import java.util.*; - -import com.oracle.graal.runtime.logging.*; -import com.oracle.graal.runtime.server.*; -import com.sun.c1x.*; -import com.sun.c1x.debug.*; -import com.sun.cri.ci.*; -import com.sun.cri.ri.*; - -/** - * Exits from the HotSpot VM into Java code. - */ -public class VMExitsNative implements VMExits, Remote { - - public static final boolean LogCompiledMethods = false; - public static boolean compileMethods = true; - - private final Compiler compiler; - - public final HotSpotTypePrimitive typeBoolean; - public final HotSpotTypePrimitive typeChar; - public final HotSpotTypePrimitive typeFloat; - public final HotSpotTypePrimitive typeDouble; - public final HotSpotTypePrimitive typeByte; - public final HotSpotTypePrimitive typeShort; - public final HotSpotTypePrimitive typeInt; - public final HotSpotTypePrimitive typeLong; - public final HotSpotTypePrimitive typeVoid; - - public VMExitsNative(Compiler compiler) { - this.compiler = compiler; - - typeBoolean = new HotSpotTypePrimitive(compiler, CiKind.Boolean); - typeChar = new HotSpotTypePrimitive(compiler, CiKind.Char); - typeFloat = new HotSpotTypePrimitive(compiler, CiKind.Float); - typeDouble = new HotSpotTypePrimitive(compiler, CiKind.Double); - typeByte = new HotSpotTypePrimitive(compiler, CiKind.Byte); - typeShort = new HotSpotTypePrimitive(compiler, CiKind.Short); - typeInt = new HotSpotTypePrimitive(compiler, CiKind.Int); - typeLong = new HotSpotTypePrimitive(compiler, CiKind.Long); - typeVoid = new HotSpotTypePrimitive(compiler, CiKind.Void); - } - - private static Set compiledMethods = new HashSet(); - - @Override - public void compileMethod(long methodVmId, String name, int entryBCI) throws Throwable { - if (!compileMethods) { - return; - } - - try { - HotSpotMethodResolved riMethod = new HotSpotMethodResolved(compiler, methodVmId, name); - CiResult result = compiler.getCompiler().compileMethod(riMethod, -1, null, null); - if (LogCompiledMethods) { - String qualifiedName = CiUtil.toJavaName(riMethod.holder()) + "::" + riMethod.name(); - compiledMethods.add(qualifiedName); - } - - if (result.bailout() != null) { - Throwable cause = result.bailout().getCause(); - if (!C1XOptions.QuietBailout) { - StringWriter out = new StringWriter(); - result.bailout().printStackTrace(new PrintWriter(out)); - TTY.println("Bailout:\n" + out.toString()); - if (cause != null) { - Logger.info("Trace for cause: "); - for (StackTraceElement e : cause.getStackTrace()) { - String current = e.getClassName() + "::" + e.getMethodName(); - String type = ""; - if (compiledMethods.contains(current)) { - type = "compiled"; - } - Logger.info(String.format("%-10s %3d %s", type, e.getLineNumber(), current)); - } - } - } - String s = result.bailout().getMessage(); - if (cause != null) { - s = cause.getMessage(); - } - compiler.getVMEntries().recordBailout(s); - } else { - HotSpotTargetMethod.installMethod(compiler, riMethod, result.targetMethod()); - } - } catch (Throwable t) { - StringWriter out = new StringWriter(); - t.printStackTrace(new PrintWriter(out)); - TTY.println("Compilation interrupted: (" + name + ")\n" + out.toString()); - throw t; - } - } - - @Override - public RiMethod createRiMethodResolved(long vmId, String name) { - return new HotSpotMethodResolved(compiler, vmId, name); - } - - @Override - public RiMethod createRiMethodUnresolved(String name, String signature, RiType holder) { - return new HotSpotMethodUnresolved(compiler, name, signature, holder); - } - - @Override - public RiSignature createRiSignature(String signature) { - return new HotSpotSignature(compiler, signature); - } - - @Override - public RiField createRiField(RiType holder, String name, RiType type, int offset, int flags) { - if (offset != -1) { - HotSpotTypeResolved resolved = (HotSpotTypeResolved) holder; - return resolved.createRiField(name, type, offset, flags); - } - return new HotSpotField(compiler, holder, name, type, offset, flags); - } - - @Override - public RiType createRiType(long vmId, String name) { - throw new RuntimeException("not implemented"); - } - - @Override - public RiType createRiTypePrimitive(int basicType) { - switch (basicType) { - case 4: - return typeBoolean; - case 5: - return typeChar; - case 6: - return typeFloat; - case 7: - return typeDouble; - case 8: - return typeByte; - case 9: - return typeShort; - case 10: - return typeInt; - case 11: - return typeLong; - case 14: - return typeVoid; - default: - throw new IllegalArgumentException("Unknown basic type: " + basicType); - } - } - - @Override - public RiType createRiTypeUnresolved(String name) { - return new HotSpotTypeUnresolved(compiler, name); - } - - @Override - public RiConstantPool createRiConstantPool(long vmId) { - return new HotSpotConstantPool(compiler, vmId); - } - - @Override - public CiConstant createCiConstant(CiKind kind, long value) { - if (kind == CiKind.Long) { - return CiConstant.forLong(value); - } else if (kind == CiKind.Int) { - return CiConstant.forInt((int) value); - } else if (kind == CiKind.Short) { - return CiConstant.forShort((short) value); - } else if (kind == CiKind.Char) { - return CiConstant.forChar((char) value); - } else if (kind == CiKind.Byte) { - return CiConstant.forByte((byte) value); - } else if (kind == CiKind.Boolean) { - return (value == 0) ? CiConstant.FALSE : CiConstant.TRUE; - } else { - throw new IllegalArgumentException(); - } - } - - @Override - public CiConstant createCiConstantFloat(float value) { - return CiConstant.forFloat(value); - } - - @Override - public CiConstant createCiConstantDouble(double value) { - return CiConstant.forDouble(value); - } - - @Override - public CiConstant createCiConstantObject(Object object) { - return CiConstant.forObject(object); - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/logging/CountingProxy.java --- a/graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/logging/CountingProxy.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,102 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.runtime.logging; - -import java.lang.reflect.*; -import java.util.*; - -import com.oracle.graal.runtime.server.*; - -/** - * A java.lang.reflect proxy that hierarchically logs all method invocations along with their parameters and return - * values. - */ -public class CountingProxy implements InvocationHandler { - - public static final boolean ENABLED = Boolean.valueOf(System.getProperty("c1x.countcalls")); - - private T delegate; - - private Map calls = new HashMap(); - - public CountingProxy(T delegate) { - assert ENABLED; - System.out.println("Counting proxy for " + delegate.getClass().getSimpleName() + " created"); - this.delegate = delegate; - proxies.add(this); - } - - @Override - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - int argCount = args == null ? 0 : args.length; - if (method.getParameterTypes().length != argCount) { - throw new RuntimeException("wrong parameter count"); - } - final Object result; - long count = calls.containsKey(method) ? calls.get(method) : 0; - calls.put(method, count + 1); - try { - if (args == null) { - result = method.invoke(delegate); - } else { - result = method.invoke(delegate, args); - } - } catch (InvocationTargetException e) { - throw e.getCause(); - } - return result; - } - - public static T getProxy(Class interf, T delegate) { - Class[] interfaces = ReplacingStreams.getAllInterfaces(delegate.getClass()); - Object obj = Proxy.newProxyInstance(interf.getClassLoader(), interfaces, new CountingProxy(delegate)); - return interf.cast(obj); - } - - private static ArrayList proxies = new ArrayList(); - - static { - if (ENABLED) { - Runtime.getRuntime().addShutdownHook(new Thread() { - - @Override - public void run() { - for (CountingProxy proxy : proxies) { - proxy.print(); - } - } - }); - } - } - - protected void print() { - long sum = 0; - for (Map.Entry entry : calls.entrySet()) { - Method method = entry.getKey(); - long count = entry.getValue(); - sum += count; - System.out.println(delegate.getClass().getSimpleName() + "." + method.getName() + ": " + count); - } - System.out.println(delegate.getClass().getSimpleName() + " calls: " + sum); - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/logging/Logger.java --- a/graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/logging/Logger.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,170 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.runtime.logging; - -import java.io.*; -import java.lang.reflect.*; -import java.util.*; - -/** - * Scoped logging class used to display the call hierarchy of VMEntries/VMExits calls. - */ -public class Logger { - - public static final boolean ENABLED = Boolean.valueOf(System.getProperty("c1x.debug")); - private static final int SPACING = 4; - private static Deque openStack = new LinkedList(); - private static boolean open = false; - private static int level = 0; - - private static final PrintStream out; - - static { - PrintStream ps = null; - String filename = System.getProperty("c1x.info_file"); - if (filename != null && !"".equals(filename)) { - try { - ps = new PrintStream(new FileOutputStream(filename)); - } catch (FileNotFoundException e) { - e.printStackTrace(); - ps = null; - } - } - out = ps; - if (out != null) { - out.println("start: " + new Date()); - } - } - - public static void info(String message) { - if (ENABLED) { - log(message); - } else { - System.out.println(message); - } - if (out != null) { - out.println(message); - out.flush(); - } - } - - public static void log(String message) { - if (ENABLED) { - for (String line : message.split("\n")) { - if (open) { - System.out.println("..."); - open = false; - } - System.out.print(space(level)); - System.out.println(line); - } - } - } - - public static void startScope(String message) { - if (ENABLED) { - if (open) { - System.out.println("..."); - open = false; - } - System.out.print(space(level)); - System.out.print(message); - openStack.push(open); - open = true; - level++; - } - } - - public static void endScope(String message) { - if (ENABLED) { - level--; - if (open) { - System.out.println(message); - } else { - System.out.println(space(level) + "..." + message); - } - open = openStack.pop(); - } - } - - private static String[] spaces = new String[50]; - - private static String space(int count) { - assert count >= 0; - String result; - if (count >= spaces.length || spaces[count] == null) { - StringBuilder str = new StringBuilder(); - for (int i = 0; i < count * SPACING; i++) { - str.append(' '); - } - result = str.toString(); - if (count < spaces.length) { - spaces[count] = result; - } - } else { - result = spaces[count]; - } - return result; - } - - public static String pretty(Object value) { - if (value == null) { - return "null"; - } - - Class klass = value.getClass(); - if (value instanceof Void) { - return "void"; - } else if (value instanceof String) { - return "\"" + value + "\""; - } else if (value instanceof Method) { - return "method \"" + ((Method) value).getName() + "\""; - } else if (value instanceof Class) { - return "class \"" + ((Class) value).getSimpleName() + "\""; - } else if (value instanceof Integer) { - if ((Integer) value < 10) { - return value.toString(); - } - return value + " (0x" + Integer.toHexString((Integer) value) + ")"; - } else if (value instanceof Long) { - if ((Long) value < 10) { - return value + "l"; - } - return value + "l (0x" + Long.toHexString((Long) value) + "l)"; - } else if (klass.isArray()) { - StringBuilder str = new StringBuilder(); - int dimensions = 0; - while (klass.isArray()) { - dimensions++; - klass = klass.getComponentType(); - } - str.append(klass.getSimpleName()).append('[').append(Array.getLength(value)).append(']'); - for (int i = 1; i < dimensions; i++) { - str.append("[]"); - } - return str.toString(); - } - - return value.toString(); - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/logging/LoggingProxy.java --- a/graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/logging/LoggingProxy.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.runtime.logging; - -import java.lang.reflect.*; - -import com.oracle.graal.runtime.server.*; - -/** - * A java.lang.reflect proxy that hierarchically logs all method invocations along with their parameters and return values. - */ -public class LoggingProxy implements InvocationHandler { - - private T delegate; - - public LoggingProxy(T delegate) { - this.delegate = delegate; - } - - @Override - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - int argCount = args == null ? 0 : args.length; - if (method.getParameterTypes().length != argCount) { - throw new RuntimeException("wrong parameter count"); - } - StringBuilder str = new StringBuilder(); - str.append(method.getReturnType().getSimpleName() + " " + method.getDeclaringClass().getSimpleName() + "." + method.getName() + "("); - for (int i = 0; i < argCount; i++) { - str.append(i == 0 ? "" : ", "); - str.append(Logger.pretty(args[i])); - } - str.append(")"); - Logger.startScope(str.toString()); - final Object result; - try { - if (args == null) { - result = method.invoke(delegate); - } else { - result = method.invoke(delegate, args); - } - } catch (InvocationTargetException e) { - Logger.endScope(" = Exception " + e.getMessage()); - throw e.getCause(); - } - Logger.endScope(" = " + Logger.pretty(result)); - return result; - } - - /** - * The object returned by this method will implement all interfaces that are implemented by delegate. - */ - public static T getProxy(Class interf, T delegate) { - Class[] interfaces = ReplacingStreams.getAllInterfaces(delegate.getClass()); - Object obj = Proxy.newProxyInstance(interf.getClassLoader(), interfaces, new LoggingProxy(delegate)); - return interf.cast(obj); - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/logging/package-info.java --- a/graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/logging/package-info.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -/** - * Logging framework for the HotSpot CRI implementation. - * - * @author Lukas Stadler - * @author Thomas Wuerthinger - */ -package com.oracle.graal.runtime.logging; diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/package-info.java --- a/graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/package-info.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -/** - * Package containing the runtime interface (defined in the CRI project) implementation for HotSpot. - * There is a class that bridges from the C++ to the Java side (VMExitsNative.java) and one that bridges - * from the Java to the C++ side (VMEntriesNative.java). - * - * @author Lukas Stadler - * @author Thomas Wuerthinger - */ -package com.oracle.graal.runtime; diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/server/CompilationServer.java --- a/graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/server/CompilationServer.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,123 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.runtime.server; - -import java.io.*; -import java.net.*; -import java.util.*; - -import javax.net.*; - -import com.oracle.graal.runtime.*; -import com.oracle.graal.runtime.Compiler; -import com.oracle.graal.runtime.logging.*; - -/** - * Server side of the client/server compilation model. The server listens for connections on the hardcoded port 1199. - * - * @author Lukas Stadler - */ -public class CompilationServer implements Runnable { - - public static void main(String[] args) throws Exception { - new CompilationServer(false).run(); - } - - public static interface ConnectionObserver { - - void connectionStarted(Compiler compiler); - - void connectionFinished(Compiler compiler); - } - - private final boolean multiple; - private final ArrayList observers = new ArrayList(); - - /** - * Creates a new Compilation server. The server is activated by calling {@link #run()} directly or via a new - * {@link Thread}. - * - * @param multiple true if the server should server should serve an infinite amount of consecutive connections, - * false if it should terminate after the first connection ends. - */ - public CompilationServer(boolean multiple) { - this.multiple = multiple; - HotSpotOptions.setDefaultOptions(); - } - - public void addConnectionObserver(ConnectionObserver observer) { - observers.add(observer); - } - - public void removeConnectionObserver(ConnectionObserver observer) { - observers.remove(observer); - } - - public void run() { - final ServerSocket serverSocket; - try { - serverSocket = ServerSocketFactory.getDefault().createServerSocket(1199); - } catch (IOException e) { - throw new RuntimeException("Couldn't create compilation server", e); - } - do { - Socket socket = null; - try { - Logger.log("Compilation server ready, waiting for client to connect..."); - socket = serverSocket.accept(); - Logger.log("Connected to " + socket.getRemoteSocketAddress()); - - ReplacingStreams streams = new ReplacingStreams(socket.getOutputStream(), socket.getInputStream()); - - // get the VMEntries proxy from the client - VMEntries entries = (VMEntries) streams.getInvocation().waitForResult(false); - - // return the initialized compiler to the client - Compiler compiler = CompilerImpl.initializeServer(entries); - compiler.getCompiler(); - streams.getInvocation().sendResult(compiler); - - for (ConnectionObserver observer : observers) { - observer.connectionStarted(compiler); - } - - streams.getInvocation().waitForResult(true); - - for (ConnectionObserver observer : observers) { - observer.connectionFinished(compiler); - } - } catch (IOException e) { - e.printStackTrace(); - } catch (ClassNotFoundException e) { - throw new RuntimeException(e); - } finally { - if (socket != null) { - try { - socket.close(); - } catch (IOException e) { - } - } - } - } while (multiple); - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/server/Remote.java --- a/graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/server/Remote.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.runtime.server; - - -public interface Remote { - -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/server/ReplacingStreams.java --- a/graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/server/ReplacingStreams.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,228 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.runtime.server; - -import java.io.*; -import java.lang.reflect.*; -import java.util.*; - -import com.oracle.graal.runtime.*; -import com.oracle.graal.runtime.Compiler; -import com.sun.cri.ci.*; - -public class ReplacingStreams { - - private IdentityHashMap objectMap = new IdentityHashMap(); - private ArrayList objectList = new ArrayList(); - - private ReplacingOutputStream output; - private ReplacingInputStream input; - - private InvocationSocket invocation; - - public ReplacingStreams(OutputStream outputStream, InputStream inputStream) throws IOException { - output = new ReplacingOutputStream(new BufferedOutputStream(outputStream)); - // required, because creating an ObjectOutputStream writes a header, but doesn't flush the stream - output.flush(); - input = new ReplacingInputStream(new BufferedInputStream(inputStream)); - invocation = new InvocationSocket(output, input); - - addStaticObject(CiValue.IllegalValue); - addStaticObject(HotSpotProxy.DUMMY_CONSTANT_OBJ); - } - - public void setInvocationSocket(InvocationSocket invocation) { - this.invocation = invocation; - } - - public ReplacingOutputStream getOutput() { - return output; - } - - public ReplacingInputStream getInput() { - return input; - } - - public InvocationSocket getInvocation() { - return invocation; - } - - private void addStaticObject(Object obj) { - int id = objectList.size(); - objectList.add(obj); - objectMap.put(obj, new Placeholder(id)); - } - - public static class Placeholder implements Serializable { - - public final int id; - - public Placeholder(int id) { - this.id = id; - } - - @Override - public String toString() { - return "#<" + id + ">"; - } - } - - public static class NewRemoteCallPlaceholder implements Serializable { - - public final Class[] interfaces; - - public NewRemoteCallPlaceholder(Class[] interfaces) { - this.interfaces = interfaces; - } - } - - public static class NewDummyPlaceholder implements Serializable { - } - - /** - * Replaces certain cir objects that cannot easily be made Serializable. - */ - public class ReplacingInputStream extends ObjectInputStream { - - private Compiler compiler; - - public ReplacingInputStream(InputStream in) throws IOException { - super(in); - enableResolveObject(true); - } - - public void setCompiler(Compiler compiler) { - this.compiler = compiler; - } - - @Override - protected Object resolveObject(Object obj) throws IOException { - // see ReplacingInputStream.replaceObject for details on when these types of objects are created - - if (obj instanceof Placeholder) { - Placeholder placeholder = (Placeholder) obj; - obj = objectList.get(placeholder.id); - return obj; - } - - if (obj instanceof NewRemoteCallPlaceholder) { - NewRemoteCallPlaceholder newPlaceholder = (NewRemoteCallPlaceholder) obj; - Placeholder placeholder = new Placeholder(objectList.size()); - obj = Proxy.newProxyInstance(getClass().getClassLoader(), newPlaceholder.interfaces, invocation.new Handler(placeholder)); - objectMap.put(obj, placeholder); - objectList.add(obj); - return obj; - } - - if (obj instanceof NewDummyPlaceholder) { - obj = new Placeholder(objectList.size()); - objectMap.put(obj, (Placeholder) obj); - objectList.add(obj); - return obj; - } - - return obj; - } - } - - /** - * Replaces certain cir objects that cannot easily be made Serializable. - */ - public class ReplacingOutputStream extends ObjectOutputStream { - - public ReplacingOutputStream(OutputStream out) throws IOException { - super(out); - enableReplaceObject(true); - } - - @Override - protected Object replaceObject(Object obj) throws IOException { - // is the object a known instance? - Placeholder placeholder = objectMap.get(obj); - if (placeholder != null) { - return placeholder; - } - - // is the object an instance of a class that will always be executed remotely? - if (obj instanceof Remote) { - return createRemoteCallPlaceholder(obj); - } - - // is the object a constant of object type? - if (obj.getClass() == CiConstant.class) { - CiConstant constant = (CiConstant) obj; - if (constant.kind != CiKind.Object) { - return obj; - } - Object contents = constant.asObject(); - if (contents == null) { - return obj; - } - // don't replace if the object already is a placeholder - if (contents instanceof Placeholder || contents instanceof Long) { - return obj; - } - placeholder = objectMap.get(contents); - if (placeholder != null) { - return CiConstant.forObject(placeholder); - } - if (contents instanceof Remote) { - return CiConstant.forObject(createRemoteCallPlaceholder(contents)); - } - return CiConstant.forObject(createDummyPlaceholder(contents)); - } - return obj; - } - } - - public static Class[] getAllInterfaces(Class clazz) { - HashSet> interfaces = new HashSet>(); - getAllInterfaces(clazz, interfaces); - return interfaces.toArray(new Class[interfaces.size()]); - } - - private static void getAllInterfaces(Class clazz, HashSet> interfaces) { - for (Class< ? > iface : clazz.getInterfaces()) { - if (!interfaces.contains(iface)) { - interfaces.add(iface); - getAllInterfaces(iface, interfaces); - } - } - if (clazz.getSuperclass() != null) { - getAllInterfaces(clazz.getSuperclass(), interfaces); - } - } - - private Object createRemoteCallPlaceholder(Object obj) { - // collect all interfaces that this object's class implements (proxies only support interfaces) - objectMap.put(obj, new Placeholder(objectList.size())); - objectList.add(obj); - return new NewRemoteCallPlaceholder(getAllInterfaces(obj.getClass())); - } - - public Object createDummyPlaceholder(Object obj) { - objectMap.put(obj, new Placeholder(objectList.size())); - objectList.add(obj); - return new NewDummyPlaceholder(); - } -} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/server/package-info.java --- a/graal/com.oracle.max.graal.runtime/src/com/oracle/graal/runtime/server/package-info.java Wed Jun 08 08:45:47 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -/** - * Implementation of a compilation server socket that delegates incoming requests to C1X. - * - * @author Lukas Stadler - * @author Thomas Wuerthinger - */ -package com.oracle.graal.runtime.server; diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/Compiler.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/Compiler.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.runtime; + +import com.oracle.max.graal.compiler.*; + +public interface Compiler { + + VMEntries getVMEntries(); + VMExits getVMExits(); + C1XCompiler getCompiler(); + +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/CompilerImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/CompilerImpl.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.runtime; + +import java.io.*; +import java.lang.management.*; +import java.net.*; + +import com.oracle.max.asm.target.amd64.*; +import com.oracle.max.graal.compiler.*; +import com.oracle.max.graal.runtime.logging.*; +import com.oracle.max.graal.runtime.server.*; +import com.sun.cri.ci.*; +import com.sun.cri.ri.*; +import com.sun.cri.xir.*; + +/** + * Singleton class holding the instance of the C1XCompiler. + */ +public final class CompilerImpl implements Compiler, Remote { + + private static Compiler theInstance; + private static boolean PrintGCStats = false; + + public static Compiler getInstance() { + return theInstance; + } + + public static void initialize() { + if (theInstance != null) { + throw new IllegalStateException("Compiler already initialized"); + } + + String remote = System.getProperty("c1x.remote"); + if (remote != null) { + // remote compilation (will not create a local Compiler) + try { + System.out.println("C1X compiler started in client/server mode, server: " + remote); + Socket socket = new Socket(remote, 1199); + ReplacingStreams streams = new ReplacingStreams(socket.getOutputStream(), socket.getInputStream()); + streams.getInvocation().sendResult(new VMEntriesNative()); + + theInstance = (Compiler) streams.getInvocation().waitForResult(false); + } catch (IOException e1) { + System.out.println("Connection to compilation server FAILED."); + throw new RuntimeException(e1); + } catch (ClassNotFoundException e2) { + System.out.println("Connection to compilation server FAILED."); + throw new RuntimeException(e2); + } + } else { + // ordinary local compilation + theInstance = new CompilerImpl(null); + Runtime.getRuntime().addShutdownHook(new ShutdownThread()); + } + } + + public static Compiler initializeServer(VMEntries entries) { + assert theInstance == null; + theInstance = new CompilerImpl(entries); + Runtime.getRuntime().addShutdownHook(new ShutdownThread()); + return theInstance; + } + + public static class ShutdownThread extends Thread { + + @Override + public void run() { + VMExitsNative.compileMethods = false; + if (C1XOptions.PrintMetrics) { + C1XMetrics.print(); + } + if (C1XOptions.PrintTimers) { + C1XTimers.print(); + } + if (PrintGCStats) { + printGCStats(); + } + } + } + + public static void printGCStats() { + long totalGarbageCollections = 0; + long garbageCollectionTime = 0; + + for (GarbageCollectorMXBean gc : ManagementFactory.getGarbageCollectorMXBeans()) { + long count = gc.getCollectionCount(); + if (count >= 0) { + totalGarbageCollections += count; + } + + long time = gc.getCollectionTime(); + if (time >= 0) { + garbageCollectionTime += time; + } + } + + System.out.println("Total Garbage Collections: " + totalGarbageCollections); + System.out.println("Total Garbage Collection Time (ms): " + garbageCollectionTime); + } + + private final VMEntries vmEntries; + private final VMExits vmExits; + private C1XCompiler compiler; + + private final HotSpotRuntime runtime; + private final CiTarget target; + private final RiXirGenerator generator; + private final RiRegisterConfig registerConfig; + + private CompilerImpl(VMEntries entries) { + + // initialize VMEntries + if (entries == null) { + entries = new VMEntriesNative(); + } + + // initialize VMExits + VMExits exits = new VMExitsNative(this); + + // logging, etc. + if (CountingProxy.ENABLED) { + exits = CountingProxy.getProxy(VMExits.class, exits); + entries = CountingProxy.getProxy(VMEntries.class, entries); + } + if (Logger.ENABLED) { + exits = LoggingProxy.getProxy(VMExits.class, exits); + entries = LoggingProxy.getProxy(VMEntries.class, entries); + } + + // set the final fields + vmEntries = entries; + vmExits = exits; + + // initialize compiler and C1XOptions + HotSpotVMConfig config = vmEntries.getConfiguration(); + config.check(); + + // these options are important - c1x4hotspot will not generate correct code without them + C1XOptions.GenSpecialDivChecks = true; + C1XOptions.NullCheckUniquePc = true; + C1XOptions.InvokeSnippetAfterArguments = true; + C1XOptions.StackShadowPages = config.stackShadowPages; + + runtime = new HotSpotRuntime(config, this); + registerConfig = runtime.globalStubRegConfig; + + final int wordSize = 8; + final int stackFrameAlignment = 16; + target = new HotSpotTarget(new AMD64(), true, wordSize, stackFrameAlignment, config.vmPageSize, wordSize, true); + + RiXirGenerator generator = new HotSpotXirGenerator(config, target, registerConfig, this); + if (Logger.ENABLED) { + this.generator = LoggingProxy.getProxy(RiXirGenerator.class, generator); + } else { + this.generator = generator; + } + + } + + @Override + public C1XCompiler getCompiler() { + if (compiler == null) { + compiler = new C1XCompiler(runtime, target, generator, registerConfig); + } + return compiler; + } + + @Override + public VMEntries getVMEntries() { + return vmEntries; + } + + @Override + public VMExits getVMExits() { + return vmExits; + } + +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/CompilerObject.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/CompilerObject.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.runtime; + +import java.io.*; + + +/** + * Parent class for all HotSpot Ri... types. + */ +public abstract class CompilerObject implements Serializable { + protected final Compiler compiler; + + protected CompilerObject(Compiler compiler) { + this.compiler = compiler; + } + +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotConstantPool.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotConstantPool.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.runtime; + +import java.io.*; +import java.util.*; + +import com.sun.cri.ri.*; + +/** + * Implementation of RiConstantPool for HotSpot. + */ +public class HotSpotConstantPool extends CompilerObject implements RiConstantPool { + + private final long vmId; + + private final FastLRUIntCache methodCache = new FastLRUIntCache(); + private final FastLRUIntCache fieldCache = new FastLRUIntCache(); + private final FastLRUIntCache typeCache = new FastLRUIntCache(); + + public static class FastLRUIntCache implements Serializable { + + private static final int InitialCapacity = 4; + private int lastKey; + private T lastObject; + + private int[] keys; + private Object[] objects; + private int count; + + @SuppressWarnings("unchecked") + private T access(int index) { + return (T) objects[index]; + } + + public T get(int key) { + if (key == lastKey) { + return lastObject; + } else if (count > 1) { + for (int i = 0; i < count; ++i) { + if (keys[i] == key) { + lastObject = access(i); + lastKey = key; + return lastObject; + } + } + } + return null; + } + + public void add(int key, T object) { + count++; + if (count == 1) { + lastKey = key; + lastObject = object; + } else { + ensureSize(); + keys[count - 1] = key; + objects[count - 1] = object; + if (count == 2) { + keys[0] = lastKey; + objects[0] = lastObject; + } + lastKey = key; + lastObject = object; + } + } + + private void ensureSize() { + if (keys == null) { + keys = new int[InitialCapacity]; + objects = new Object[InitialCapacity]; + } else if (count > keys.length) { + keys = Arrays.copyOf(keys, keys.length * 2); + objects = Arrays.copyOf(objects, objects.length * 2); + } + } + } + + public HotSpotConstantPool(Compiler compiler, long vmId) { + super(compiler); + this.vmId = vmId; + } + + @Override + public Object lookupConstant(int cpi) { + Object constant = compiler.getVMEntries().RiConstantPool_lookupConstant(vmId, cpi); + return constant; + } + + @Override + public RiSignature lookupSignature(int cpi) { + return compiler.getVMEntries().RiConstantPool_lookupSignature(vmId, cpi); + } + + @Override + public RiMethod lookupMethod(int cpi, int byteCode) { + RiMethod result = methodCache.get(cpi); + if (result == null) { + result = compiler.getVMEntries().RiConstantPool_lookupMethod(vmId, cpi, (byte) byteCode); + methodCache.add(cpi, result); + } + return result; + } + + @Override + public RiType lookupType(int cpi, int opcode) { + RiType result = typeCache.get(cpi); + if (result == null) { + result = compiler.getVMEntries().RiConstantPool_lookupType(vmId, cpi); + typeCache.add(cpi, result); + } + return result; + } + + @Override + public RiField lookupField(int cpi, int opcode) { + RiField result = fieldCache.get(cpi); + if (result == null) { + result = compiler.getVMEntries().RiConstantPool_lookupField(vmId, cpi, (byte) opcode); + fieldCache.add(cpi, result); + } + return result; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotExceptionHandler.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotExceptionHandler.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.runtime; + +import com.sun.cri.ri.*; + + +public class HotSpotExceptionHandler extends CompilerObject implements RiExceptionHandler { + private int startBci; + private int endBci; + private int handlerBci; + private int catchClassIndex; + private RiType catchClass; + + public HotSpotExceptionHandler() { + super(null); + } + + @Override + public int startBCI() { + return startBci; + } + + @Override + public int endBCI() { + return endBci; + } + + @Override + public int handlerBCI() { + return handlerBci; + } + + @Override + public int catchTypeCPI() { + return catchClassIndex; + } + + @Override + public boolean isCatchAll() { + return catchClassIndex == 0; + } + + @Override + public RiType catchType() { + return catchClass; + } + +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotField.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotField.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.max.graal.runtime; + +import java.lang.reflect.*; + +import com.oracle.max.graal.compiler.*; +import com.sun.cri.ci.CiConstant; +import com.sun.cri.ci.CiKind; +import com.sun.cri.ri.RiField; +import com.sun.cri.ri.RiType; + +/** + * Represents a field in a HotSpot type. + */ +public class HotSpotField extends CompilerObject implements RiField { + + private final RiType holder; + private final String name; + private final RiType type; + private final int offset; + private final int accessFlags; + private CiConstant constant; + + public HotSpotField(Compiler compiler, RiType holder, String name, RiType type, int offset, int accessFlags) { + super(compiler); + this.holder = holder; + this.name = name; + this.type = type; + this.offset = offset; + this.accessFlags = accessFlags; + } + + @Override + public int accessFlags() { + return accessFlags; + } + + @Override + public CiConstant constantValue(CiConstant receiver) { + if (receiver == null) { + if (constant == null && holder.isResolved() && holder.isSubtypeOf(compiler.getVMEntries().getType(C1XOptions.class))) { + Field f; + try { + f = C1XOptions.class.getField(name); + } catch (SecurityException e1) { + return null; + } catch (NoSuchFieldException e1) { + return null; + } + f.setAccessible(true); + if (Modifier.isStatic(f.getModifiers())) { + CiKind kind = CiKind.fromJavaClass(f.getType()); + Object value; + try { + value = f.get(null); + } catch (IllegalArgumentException e) { + return null; + } catch (IllegalAccessException e) { + return null; + } + constant = CiConstant.forBoxed(kind, value); + } + } + + // Constant part only valid for static fields. + return constant; + } + return null; + } + + @Override + public RiType holder() { + return holder; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof HotSpotField) { + HotSpotField other = (HotSpotField) obj; + return other.offset == offset && other.holder.equals(holder()); + } + return false; + } + + @Override + public boolean isResolved() { + return offset != -1; + } + + @Override + public CiKind kind() { + return type().kind(); + } + + @Override + public String name() { + return name; + } + + @Override + public RiType type() { + return type; + } + + public int offset() { + return offset; + } + + @Override + public String toString() { + return "HotSpotField<" + holder.name() + "." + name + ">"; + } + +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotMethod.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotMethod.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.runtime; + +import com.sun.cri.ri.*; + + +public abstract class HotSpotMethod extends CompilerObject implements RiMethod { + + protected RiType holder; + protected String name; + + protected HotSpotMethod(Compiler compiler) { + super(compiler); + } + + @Override + public final RiType holder() { + return holder; + } + + @Override + public final String name() { + return name; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotMethodResolved.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotMethodResolved.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.runtime; + +import java.lang.reflect.*; + +import com.sun.cri.ci.*; +import com.sun.cri.ri.*; + +/** + * Implementation of RiMethod for resolved HotSpot methods. + */ +public final class HotSpotMethodResolved extends HotSpotMethod { + + private final long vmId; + + // cached values + private byte[] code; + private int accessFlags = -1; + private int maxLocals = -1; + private int maxStackSize = -1; + private RiExceptionHandler[] exceptionHandlers; + private RiSignature signature; + private Boolean hasBalancedMonitors; + + public HotSpotMethodResolved(Compiler compiler, long vmId, String name) { + super(compiler); + this.vmId = vmId; + this.name = name; + this.holder = compiler.getVMEntries().RiMethod_holder(vmId); + } + + @Override + public int accessFlags() { + if (accessFlags == -1) { + accessFlags = compiler.getVMEntries().RiMethod_accessFlags(vmId); + } + return accessFlags; + } + + @Override + public boolean canBeStaticallyBound() { + return isLeafMethod() || Modifier.isStatic(accessFlags()); + } + + @Override + public byte[] code() { + if (code == null) { + code = compiler.getVMEntries().RiMethod_code(vmId); + } + return code; + } + + @Override + public RiExceptionHandler[] exceptionHandlers() { + if (exceptionHandlers == null) { + exceptionHandlers = compiler.getVMEntries().RiMethod_exceptionHandlers(vmId); + } + return exceptionHandlers; + } + + @Override + public boolean hasBalancedMonitors() { + if (hasBalancedMonitors == null) { + hasBalancedMonitors = compiler.getVMEntries().RiMethod_hasBalancedMonitors(vmId); + } + return hasBalancedMonitors; + } + + @Override + public boolean isClassInitializer() { + return "".equals(name); + } + + @Override + public boolean isConstructor() { + return "".equals(name); + } + + @Override + public boolean isLeafMethod() { + return Modifier.isFinal(accessFlags()) || Modifier.isPrivate(accessFlags()); + } + + @Override + public boolean isOverridden() { + throw new UnsupportedOperationException("isOverridden"); + } + + @Override + public boolean noSafepoints() { + return false; + } + + @Override + public boolean isResolved() { + return true; + } + + @Override + public String jniSymbol() { + throw new UnsupportedOperationException("jniSymbol"); + } + + public CiBitMap[] livenessMap() { + return null; + } + + @Override + public int maxLocals() { + if (maxLocals == -1) { + maxLocals = compiler.getVMEntries().RiMethod_maxLocals(vmId); + } + return maxLocals; + } + + @Override + public int maxStackSize() { + if (maxStackSize == -1) { + maxStackSize = compiler.getVMEntries().RiMethod_maxStackSize(vmId); + } + return maxStackSize; + } + + @Override + public RiMethodProfile methodData() { + return null; + } + + @Override + public StackTraceElement toStackTraceElement(int bci) { + return CiUtil.toStackTraceElement(this, bci); + } + + public RiMethod uniqueConcreteMethod() { + return compiler.getVMEntries().RiMethod_uniqueConcreteMethod(vmId); + } + + @Override + public RiSignature signature() { + if (signature == null) { + signature = new HotSpotSignature(compiler, compiler.getVMEntries().RiMethod_signature(vmId)); + } + return signature; + } + + @Override + public String toString() { + return "HotSpotMethod<" + holder().name() + ". " + name + ">"; + } + + public boolean hasCompiledCode() { + // TODO: needs a VMEntries to go cache the result of that method. + // This isn't used by GRAAL for now, so this is enough. + return false; + } + + @Override + public RiType accessor() { + return null; + } + + @Override + public int intrinsic() { + return 0; + } + + @Override + public boolean minimalDebugInfo() { + return false; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotMethodUnresolved.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotMethodUnresolved.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.runtime; + +import com.sun.cri.ci.*; +import com.sun.cri.ri.*; + +/** + * Implementation of RiMethod for unresolved HotSpot methods. + */ +public final class HotSpotMethodUnresolved extends HotSpotMethod { + private final RiSignature signature; + + public HotSpotMethodUnresolved(Compiler compiler, String name, String signature, RiType holder) { + super(compiler); + this.name = name; + this.holder = holder; + this.signature = new HotSpotSignature(compiler, signature); + } + + @Override + public RiSignature signature() { + return signature; + } + + @Override + public boolean isResolved() { + return false; + } + + @Override + public byte[] code() { + throw unresolved("code"); + } + + @Override + public RiMethodProfile methodData() { + throw unresolved("methodData"); + } + + @Override + public String jniSymbol() { + throw unresolved("jniSymbol"); + } + + @Override + public int maxLocals() { + throw unresolved("maxLocals"); + } + + @Override + public int maxStackSize() { + throw unresolved("maxStackSize"); + } + + @Override + public boolean hasBalancedMonitors() { + throw unresolved("hasBalancedMonitors"); + } + + @Override + public int accessFlags() { + throw unresolved("accessFlags"); + } + + @Override + public boolean isLeafMethod() { + throw unresolved("isLeafMethod"); + } + + @Override + public boolean isClassInitializer() { + return "".equals(name); + } + + @Override + public boolean isConstructor() { + return "".equals(name); + } + + @Override + public boolean isOverridden() { + throw unresolved("isOverridden"); + } + + @Override + public boolean noSafepoints() { + return false; + } + + @Override + public CiBitMap[] livenessMap() { + return null; + } + + @Override + public StackTraceElement toStackTraceElement(int bci) { + return CiUtil.toStackTraceElement(this, bci); + } + + @Override + public boolean canBeStaticallyBound() { + throw unresolved("canBeStaticallyBound"); + } + + @Override + public RiExceptionHandler[] exceptionHandlers() { + throw unresolved("exceptionHandlers"); + } + + @Override + public boolean minimalDebugInfo() { + throw unresolved("minimalDebugInfo"); + } + + private CiUnresolvedException unresolved(String operation) { + return new CiUnresolvedException(operation + " not defined for unresolved method " + name); + } + + @Override + public String toString() { + return "HotSpotMethod<" + holder.name() + ". " + name + ", unresolved>"; + } + + public boolean hasCompiledCode() { + return false; + } + + @Override + public RiType accessor() { + return null; + } + + @Override + public int intrinsic() { + return 0; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotOptions.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotOptions.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.max.graal.runtime; + +import java.lang.reflect.*; + +import com.oracle.max.graal.compiler.*; +import com.oracle.max.graal.runtime.logging.*; + +public class HotSpotOptions { + + public static void setDefaultOptions() { + C1XOptions.CommentedAssembly = false; + C1XOptions.MethodEndBreakpointGuards = 2; + C1XOptions.ResolveClassBeforeStaticInvoke = false; + } + + public static boolean setOption(String option) { + if (option.length() == 0) { + return false; + } + + Object value = null; + String fieldName = null; + String valueString = null; + + char first = option.charAt(0); + if (first == '+' || first == '-') { + fieldName = option.substring(1); + value = (first == '+'); + } else { + int index = option.indexOf('='); + if (index == -1) { + return false; + } + fieldName = option.substring(0, index); + valueString = option.substring(index + 1); + } + + Field f; + try { + f = C1XOptions.class.getField(fieldName); + + if (value == null) { + if (f.getType() == Float.TYPE) { + value = Float.parseFloat(valueString); + } else if (f.getType() == Double.TYPE) { + value = Double.parseDouble(valueString); + } else if (f.getType() == Integer.TYPE) { + value = Integer.parseInt(valueString); + } else if (f.getType() == Boolean.TYPE) { + value = Boolean.parseBoolean(valueString); + } else if (f.getType() == String.class) { + value = valueString; + } + } + if (value != null) { + f.set(null, value); + //Logger.info("Set option " + fieldName + " to " + value); + } else { + Logger.info("Wrong value \"" + valueString + "\" for option " + fieldName); + return false; + } + } catch (SecurityException e) { + Logger.info("Security exception when setting option " + option); + return false; + } catch (NoSuchFieldException e) { + Logger.info("Could not find option " + fieldName); + return false; + } catch (IllegalArgumentException e) { + Logger.info("Illegal value for option " + option); + return false; + } catch (IllegalAccessException e) { + Logger.info("Illegal access exception when setting option " + option); + return false; + } + + return true; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotProxy.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotProxy.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.runtime; + +/** + * Provides methods to classify the HotSpot-internal identifiers. + */ +public final class HotSpotProxy { + + private HotSpotProxy() { + } + + private enum CompilerObjectType { + // this enum needs to have the same values as the one in c1x_Compiler.hpp + STUB(0x100000000000000L), + METHOD(0x200000000000000L), + CLASS(0x300000000000000L), + SYMBOL(0x400000000000000L), + CONSTANT_POOL(0x500000000000000L), + CONSTANT(0x600000000000000L), + TYPE_MASK(0xf00000000000000L), + DUMMY_CONSTANT(0x6ffffffffffffffL); + + public final long bits; + + CompilerObjectType(long bits) { + this.bits = bits; + } + } + + public static final Long DUMMY_CONSTANT_OBJ = CompilerObjectType.DUMMY_CONSTANT.bits; + + private static boolean isType(long id, CompilerObjectType type) { + return (id & CompilerObjectType.TYPE_MASK.bits) == type.bits; + } + + public static boolean isStub(long id) { + return isType(id, CompilerObjectType.STUB); + } + + public static boolean isMethod(long id) { + return isType(id, CompilerObjectType.METHOD); + } + + public static boolean isClass(long id) { + return isType(id, CompilerObjectType.CLASS); + } + + public static boolean isSymbol(long id) { + return isType(id, CompilerObjectType.SYMBOL); + } + + public static boolean isConstantPool(long id) { + return isType(id, CompilerObjectType.CONSTANT_POOL); + } + + public static boolean isConstant(long id) { + return isType(id, CompilerObjectType.CONSTANT_POOL); + } + + public static String toString(long id) { + CompilerObjectType type = null; + for (CompilerObjectType t : CompilerObjectType.values()) { + if ((id & CompilerObjectType.TYPE_MASK.bits) == t.bits) { + type = t; + } + } + long num = id & ~CompilerObjectType.TYPE_MASK.bits; + return type + " " + num; + } + +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotRegisterConfig.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotRegisterConfig.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,209 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.runtime; + +import static com.oracle.max.asm.target.amd64.AMD64.*; + +import java.util.*; + +import com.oracle.max.asm.target.amd64.*; +import com.oracle.max.graal.compiler.util.*; +import com.sun.cri.ci.*; +import com.sun.cri.ci.CiCallingConvention.Type; +import com.sun.cri.ci.CiRegister.RegisterFlag; +import com.sun.cri.ri.*; + +public class HotSpotRegisterConfig implements RiRegisterConfig { + + // be careful - the contents of this array are duplicated in c1x_CodeInstaller.cpp + private final CiRegister[] allocatable = { + rax, rbx, rcx, rdx, rsi, rdi, r8, r9, /* r10, */r11, r12, r13, r14, /*r15*/ + xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, + xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15 + }; + + private final EnumMap categorized = CiRegister.categorize(allocatable); + + private final RiRegisterAttributes[] attributesMap; + + @Override + public CiRegister[] getAllocatableRegisters() { + return allocatable; + } + + @Override + public EnumMap getCategorizedAllocatableRegisters() { + return categorized; + } + + @Override + public RiRegisterAttributes[] getAttributesMap() { + return attributesMap; + } + + private final CiRegister[] generalParameterRegisters; + private final CiRegister[] xmmParameterRegisters = {xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7}; + private final CiRegister[] allParameterRegisters; + + private final CiRegister[] rsaRegs = { + rax, rcx, rdx, rbx, rsp, rbp, rsi, rdi, + r8, r9, r10, r11, r12, r13, r14, r15, + xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, + xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15 + }; + + private final CiCalleeSaveArea registerSaveArea; + + + public HotSpotRegisterConfig(HotSpotVMConfig config, boolean globalStubConfig) { + if (config.windowsOs) { + generalParameterRegisters = new CiRegister[] {rdx, r8, r9, rdi, rsi, rcx}; + } else { + generalParameterRegisters = new CiRegister[] {rsi, rdx, rcx, r8, r9, rdi}; + } + + if (globalStubConfig) { + registerSaveArea = new CiCalleeSaveArea(-1, 8, rsaRegs); + } else { + registerSaveArea = CiCalleeSaveArea.EMPTY; + } + + attributesMap = RiRegisterAttributes.createMap(this, AMD64.allRegisters); + allParameterRegisters = Arrays.copyOf(generalParameterRegisters, generalParameterRegisters.length + xmmParameterRegisters.length); + System.arraycopy(xmmParameterRegisters, 0, allParameterRegisters, generalParameterRegisters.length, xmmParameterRegisters.length); + } + + @Override + public CiRegister[] getCallerSaveRegisters() { + return getAllocatableRegisters(); + } + + @Override + public CiRegister getRegisterForRole(int index) { + throw new UnsupportedOperationException(); + } + + @Override + public CiCallingConvention getCallingConvention(Type type, CiKind[] parameters, CiTarget target) { + if (type == Type.NativeCall) { + throw new UnsupportedOperationException(); + } + return callingConvention(parameters, type, target); + } + + public CiRegister[] getCallingConventionRegisters(Type type, RegisterFlag flag) { + return allParameterRegisters; + } + + private CiCallingConvention callingConvention(CiKind[] types, Type type, CiTarget target) { + CiValue[] locations = new CiValue[types.length]; + + int currentGeneral = 0; + int currentXMM = 0; + int currentStackIndex = 0; + + for (int i = 0; i < types.length; i++) { + final CiKind kind = types[i]; + + switch (kind) { + case Byte: + case Boolean: + case Short: + case Char: + case Int: + case Long: + case Word: + case Object: + if (currentGeneral < generalParameterRegisters.length) { + CiRegister register = generalParameterRegisters[currentGeneral++]; + locations[i] = register.asValue(kind); + } + break; + case Float: + case Double: + if (currentXMM < xmmParameterRegisters.length) { + CiRegister register = xmmParameterRegisters[currentXMM++]; + locations[i] = register.asValue(kind); + } + break; + default: + throw Util.shouldNotReachHere(); + } + + if (locations[i] == null) { + // we need to adjust for the frame pointer stored on the stack, which shifts incoming arguments by one slot + locations[i] = CiStackSlot.get(kind.stackKind(), currentStackIndex + (type.out ? 0 : 1), !type.out); + currentStackIndex += target.spillSlots(kind); + } + } + + return new CiCallingConvention(locations, currentStackIndex * target.spillSlotSize); + } + + @Override + public CiRegister getReturnRegister(CiKind kind) { + switch (kind) { + case Boolean: + case Byte: + case Char: + case Short: + case Int: + case Long: + case Object: + case Word: + return rax; + case Float: + case Double: + return xmm0; + case Void: + case Illegal: + return null; + default: + throw new UnsupportedOperationException("no return register for type " + kind); + } + } + + @Override + public CiRegister getScratchRegister() { + return r10; + } + + @Override + public CiRegister getFrameRegister() { + return rsp; + } + + public CiCalleeSaveArea getCalleeSaveArea() { + return registerSaveArea; + } + + @Override + public String toString() { + String res = String.format( + "Allocatable: " + Arrays.toString(getAllocatableRegisters()) + "%n" + + "CallerSave: " + Arrays.toString(getCallerSaveRegisters()) + "%n" + + "CalleeSave: " + getCalleeSaveArea() + "%n" + + "Scratch: " + getScratchRegister() + "%n"); + return res; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotRuntime.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotRuntime.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,245 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.runtime; + +import java.io.*; +import java.lang.reflect.*; +import java.util.*; + +import com.sun.cri.ci.*; +import com.sun.cri.ci.CiTargetMethod.Call; +import com.sun.cri.ci.CiTargetMethod.DataPatch; +import com.sun.cri.ci.CiTargetMethod.Safepoint; +import com.sun.cri.ri.*; +import com.sun.max.asm.dis.*; +import com.sun.max.lang.*; + +/** + * CRI runtime implementation for the HotSpot VM. + */ +public class HotSpotRuntime implements RiRuntime { + + final HotSpotVMConfig config; + final HotSpotRegisterConfig regConfig; + final HotSpotRegisterConfig globalStubRegConfig; + private final Compiler compiler; + + + public HotSpotRuntime(HotSpotVMConfig config, Compiler compiler) { + this.config = config; + this.compiler = compiler; + regConfig = new HotSpotRegisterConfig(config, false); + globalStubRegConfig = new HotSpotRegisterConfig(config, true); + } + + @Override + public int codeOffset() { + return 0; + } + + @Override + public String disassemble(byte[] code, long address) { + return disassemble(code, new DisassemblyPrinter(false), address); + } + + private String disassemble(byte[] code, DisassemblyPrinter disassemblyPrinter, long address) { + final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + final ISA instructionSet = ISA.AMD64; + Disassembler.disassemble(byteArrayOutputStream, code, instructionSet, WordWidth.BITS_64, address, null, disassemblyPrinter); + return byteArrayOutputStream.toString(); + } + + @Override + public String disassemble(final CiTargetMethod targetMethod) { + + final DisassemblyPrinter disassemblyPrinter = new DisassemblyPrinter(false) { + + private String toString(Call call) { + if (call.runtimeCall != null) { + return "{" + call.runtimeCall.name() + "}"; + } else if (call.symbol != null) { + return "{" + call.symbol + "}"; + } else if (call.globalStubID != null) { + return "{" + call.globalStubID + "}"; + } else { + return "{" + call.method + "}"; + } + } + + private String siteInfo(int pcOffset) { + for (Call call : targetMethod.directCalls) { + if (call.pcOffset == pcOffset) { + return toString(call); + } + } + for (Call call : targetMethod.indirectCalls) { + if (call.pcOffset == pcOffset) { + return toString(call); + } + } + for (Safepoint site : targetMethod.safepoints) { + if (site.pcOffset == pcOffset) { + return "{safepoint}"; + } + } + for (DataPatch site : targetMethod.dataReferences) { + if (site.pcOffset == pcOffset) { + return "{" + site.constant + "}"; + } + } + return null; + } + + @Override + protected String disassembledObjectString(Disassembler disassembler, DisassembledObject disassembledObject) { + final String string = super.disassembledObjectString(disassembler, disassembledObject); + + String site = siteInfo(disassembledObject.startPosition()); + if (site != null) { + return string + " " + site; + } + return string; + } + }; + final byte[] code = Arrays.copyOf(targetMethod.targetCode(), targetMethod.targetCodeSize()); + return disassemble(code, disassemblyPrinter, 0L); + } + + @Override + public String disassemble(RiMethod method) { + return "No disassembler available"; + } + + @Override + public RiConstantPool getConstantPool(RiMethod method) { + return ((HotSpotTypeResolved) method.holder()).constantPool(); + } + + @Override + public RiOsrFrame getOsrFrame(RiMethod method, int bci) { + return null; + } + + public Class getJavaClass(CiConstant c) { + return null; + } + + @Override + public RiType asRiType(CiKind kind) { + return compiler.getVMEntries().getType(kind.toJavaClass()); + } + + @Override + public RiType getTypeOf(CiConstant constant) { + return compiler.getVMEntries().getRiType(constant); + } + + @Override + public boolean isExceptionType(RiType type) { + return type.isSubtypeOf(compiler.getVMEntries().getType(Throwable.class)); + } + + @Override + public RiSnippets getSnippets() { + throw new UnsupportedOperationException("getSnippets"); + } + + @Override + public boolean mustInline(RiMethod method) { + return false; + } + + @Override + public boolean mustNotCompile(RiMethod method) { + return false; + } + + @Override + public boolean mustNotInline(RiMethod method) { + return Modifier.isNative(method.accessFlags()); + } + + @Override + public Object registerGlobalStub(CiTargetMethod targetMethod, String name) { + return HotSpotTargetMethod.installStub(compiler, targetMethod, name); + } + + @Override + public int sizeOfBasicObjectLock() { + // TODO shouldn't be hard coded + return 2 * 8; + } + + @Override + public int basicObjectLockOffsetInBytes() { + return 8; + } + + @Override + public CiConstant invoke(RiMethod method, CiMethodInvokeArguments args) { + return null; + } + + @Override + public CiConstant foldWordOperation(int opcode, CiMethodInvokeArguments args) { + throw new UnsupportedOperationException("foldWordOperation"); + } + + @Override + public boolean areConstantObjectsEqual(CiConstant x, CiConstant y) { + return compiler.getVMEntries().compareConstantObjects(x, y); + } + + @Override + public RiRegisterConfig getRegisterConfig(RiMethod method) { + return regConfig; + } + + /** + * HotSpots needs an area suitable for storing a program counter for temporary use during the deoptimization process. + */ + @Override + public int getCustomStackAreaSize() { + return 8; + } + + @Override + public boolean supportsArrayIntrinsics() { + return true; + } + + @Override + public int getArrayLength(CiConstant array) { + return compiler.getVMEntries().getArrayLength(array); + } + + @Override + public Class asJavaClass(CiConstant c) { + return null; + } + + @Override + public Object asJavaObject(CiConstant c) { + return null; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotSignature.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotSignature.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.runtime; + +import java.util.*; + +import com.sun.cri.ci.*; +import com.sun.cri.ri.*; + +/** + * Represents a method signature. + */ +public class HotSpotSignature extends CompilerObject implements RiSignature { + + private final List arguments = new ArrayList(); + private final String returnType; + private final String originalString; + private RiType[] argumentTypes; + private RiType returnTypeCache; + + public HotSpotSignature(Compiler compiler, String signature) { + super(compiler); + assert signature.length() > 0; + this.originalString = signature; + + if (signature.charAt(0) == '(') { + int cur = 1; + while (cur < signature.length() && signature.charAt(cur) != ')') { + int nextCur = parseSignature(signature, cur); + arguments.add(signature.substring(cur, nextCur)); + cur = nextCur; + } + + cur++; + int nextCur = parseSignature(signature, cur); + returnType = signature.substring(cur, nextCur); + assert nextCur == signature.length(); + } else { + returnType = null; + } + } + + private int parseSignature(String signature, int cur) { + char first; + do { + first = signature.charAt(cur++); + } while (first == '['); + + switch (first) { + case 'L': + while (signature.charAt(cur) != ';') { + cur++; + } + cur++; + break; + case 'V': + case 'I': + case 'B': + case 'C': + case 'D': + case 'F': + case 'J': + case 'S': + case 'Z': + break; + default: + assert false; + } + return cur; + } + + @Override + public int argumentCount(boolean withReceiver) { + return arguments.size() + (withReceiver ? 1 : 0); + } + + @Override + public CiKind argumentKindAt(int index) { + return CiKind.fromTypeString(arguments.get(index)); + } + + @Override + public int argumentSlots(boolean withReceiver) { + + int argSlots = 0; + for (int i = 0; i < argumentCount(false); i++) { + argSlots += argumentKindAt(i).sizeInSlots(); + } + + return argSlots + (withReceiver ? 1 : 0); + } + + @Override + public RiType argumentTypeAt(int index, RiType accessingClass) { + if (argumentTypes == null) { + argumentTypes = new RiType[arguments.size()]; + } + RiType type = argumentTypes[index]; + if (type == null) { + type = compiler.getVMEntries().RiSignature_lookupType(arguments.get(index), (HotSpotTypeResolved) accessingClass); + argumentTypes[index] = type; + } + return type; + } + + @Override + public String asString() { + return originalString; + } + + @Override + public CiKind returnKind() { + return CiKind.fromTypeString(returnType); + } + + @Override + public RiType returnType(RiType accessingClass) { + if (returnTypeCache == null) { + returnTypeCache = compiler.getVMEntries().RiSignature_lookupType(returnType, (HotSpotTypeResolved) accessingClass); + } + return returnTypeCache; + } + + @Override + public String toString() { + return "HotSpotSignature<" + originalString + ">"; + } + +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotTarget.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotTarget.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.runtime; + +import com.sun.cri.ci.*; + +/** + * HotSpot-specific CiTarget that provides the correct stack frame size alignment. + */ +public class HotSpotTarget extends CiTarget { + + public HotSpotTarget(CiArchitecture arch, boolean isMP, int spillSlotSize, int stackAlignment, int pageSize, int cacheAlignment, boolean inlineObjects) { + super(arch, isMP, spillSlotSize, stackAlignment, pageSize, cacheAlignment, inlineObjects, true); + } + + @Override + public int alignFrameSize(int frameSize) { + // account for the stored rbp value + return super.alignFrameSize(frameSize + wordSize) - wordSize; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotTargetMethod.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotTargetMethod.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.runtime; + +import java.util.*; + +import com.oracle.max.graal.runtime.logging.*; +import com.sun.cri.ci.*; +import com.sun.cri.ci.CiTargetMethod.*; + +/** + * CiTargetMethod augmented with HotSpot-specific information. + */ +public final class HotSpotTargetMethod extends CompilerObject { + + public final CiTargetMethod targetMethod; + public final HotSpotMethodResolved method; // used only for methods + public final String name; // used only for stubs + + public final Site[] sites; + public final ExceptionHandler[] exceptionHandlers; + + private HotSpotTargetMethod(Compiler compiler, HotSpotMethodResolved method, CiTargetMethod targetMethod) { + super(compiler); + this.method = method; + this.targetMethod = targetMethod; + this.name = null; + + sites = getSortedSites(targetMethod); + if (targetMethod.exceptionHandlers == null) { + exceptionHandlers = null; + } else { + exceptionHandlers = targetMethod.exceptionHandlers.toArray(new ExceptionHandler[targetMethod.exceptionHandlers.size()]); + } + } + + private HotSpotTargetMethod(Compiler compiler, CiTargetMethod targetMethod, String name) { + super(compiler); + this.method = null; + this.targetMethod = targetMethod; + this.name = name; + + sites = getSortedSites(targetMethod); + assert targetMethod.exceptionHandlers == null || targetMethod.exceptionHandlers.size() == 0; + exceptionHandlers = null; + } + + private Site[] getSortedSites(CiTargetMethod target) { + List[] lists = new List[] {target.directCalls, target.indirectCalls, target.safepoints, target.dataReferences, target.marks}; + int count = 0; + for (List list : lists) { + count += list.size(); + } + Site[] result = new Site[count]; + int pos = 0; + for (List list : lists) { + for (Object elem : list) { + result[pos++] = (Site) elem; + } + } + Arrays.sort(result, new Comparator() { + + public int compare(Site s1, Site s2) { + if (s1.pcOffset == s2.pcOffset && (s1 instanceof Mark ^ s2 instanceof Mark)) { + return s1 instanceof Mark ? -1 : 1; + } + return s1.pcOffset - s2.pcOffset; + } + }); + if (Logger.ENABLED) { + for (Site site : result) { + Logger.log(site.pcOffset + ": " + site); + } + } + return result; + } + + public static void installMethod(Compiler compiler, HotSpotMethodResolved method, CiTargetMethod targetMethod) { + compiler.getVMEntries().installMethod(new HotSpotTargetMethod(compiler, method, targetMethod)); + } + + public static Object installStub(Compiler compiler, CiTargetMethod targetMethod, String name) { + return compiler.getVMEntries().installStub(new HotSpotTargetMethod(compiler, targetMethod, name)); + } + +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotType.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotType.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.runtime; + +import com.sun.cri.ri.*; + +/** + * Common interface for all HotSpot RiType-implementations. + */ +public abstract class HotSpotType extends CompilerObject implements RiType { + protected String name; + + protected HotSpotType(Compiler compiler) { + super(compiler); + } + + @Override + public final String name() { + return name; + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotTypePrimitive.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotTypePrimitive.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.runtime; + +import com.oracle.max.graal.compiler.util.*; +import com.sun.cri.ci.*; +import com.sun.cri.ri.*; + +/** + * Implementation of RiType for primitive HotSpot types. + */ +public final class HotSpotTypePrimitive extends HotSpotType { + + private CiKind kind; + + + HotSpotTypePrimitive(Compiler compiler, CiKind kind) { + super(compiler); + this.kind = kind; + this.name = kind.toString(); + } + + @Override + public int accessFlags() { + return kind.toJavaClass().getModifiers(); + } + + @Override + public RiType arrayOf() { + return compiler.getVMEntries().getPrimitiveArrayType(kind); + } + + @Override + public RiType componentType() { + return null; + } + + @Override + public RiType exactType() { + return this; + } + + @Override + public RiType superType() { + return null; + } + + @Override + public CiConstant getEncoding(Representation r) { + throw Util.unimplemented("HotSpotTypePrimitive.getEncoding"); + } + + @Override + public CiKind getRepresentationKind(Representation r) { + return kind; + } + + @Override + public boolean hasFinalizableSubclass() { + return false; + } + + @Override + public boolean hasFinalizer() { + return false; + } + + @Override + public boolean hasSubclass() { + return false; + } + + @Override + public boolean isArrayClass() { + return false; + } + + @Override + public boolean isInitialized() { + return true; + } + + @Override + public boolean isInstance(CiConstant obj) { + return false; + } + + @Override + public boolean isInstanceClass() { + return false; + } + + @Override + public boolean isInterface() { + return false; + } + + @Override + public boolean isResolved() { + return true; + } + + @Override + public boolean isSubtypeOf(RiType other) { + return false; + } + + @Override + public CiKind kind() { + return kind; + } + + @Override + public RiMethod resolveMethodImpl(RiMethod method) { + return null; + } + + @Override + public String toString() { + return "HotSpotTypePrimitive<" + kind + ">"; + } + + @Override + public RiType uniqueConcreteSubtype() { + return this; + } + + @Override + public RiMethod uniqueConcreteMethod(RiMethod method) { + return null; + } + +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotTypeResolved.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotTypeResolved.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.runtime; + +import com.oracle.max.graal.runtime.server.*; +import com.sun.cri.ri.*; + +public interface HotSpotTypeResolved extends RiType, Remote { + + String toString(); + + RiConstantPool constantPool(); + + int instanceSize(); + + RiField createRiField(String name, RiType type, int offset, int flags); + +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotTypeResolvedImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotTypeResolvedImpl.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,226 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.runtime; + +import java.lang.reflect.*; +import java.util.*; + +import com.sun.cri.ci.*; +import com.sun.cri.ri.*; + +/** + * Implementation of RiType for resolved non-primitive HotSpot classes. + */ +public final class HotSpotTypeResolvedImpl extends HotSpotType implements HotSpotTypeResolved { + + private Class javaMirror; + private String simpleName; + private int accessFlags; + private boolean hasFinalizer; + private boolean hasSubclass; + private boolean hasFinalizableSubclass; + private boolean isInitialized; + private boolean isArrayClass; + private boolean isInstanceClass; + private boolean isInterface; + private int instanceSize; + private RiType componentType; + private HashMap fieldCache; + private RiConstantPool pool; + private RiType superType; + private boolean superTypeSet; + + private HotSpotTypeResolvedImpl() { + super(null); + } + + @Override + public int accessFlags() { + return accessFlags; + } + + @Override + public RiType arrayOf() { + return compiler.getVMEntries().RiType_arrayOf(this); + } + + @Override + public RiType componentType() { + return compiler.getVMEntries().RiType_componentType(this); + } + + @Override + public RiType uniqueConcreteSubtype() { + return compiler.getVMEntries().RiType_uniqueConcreteSubtype(this); + } + + @Override + public RiType superType() { + if (!superTypeSet) { + superType = compiler.getVMEntries().RiType_superType(this); + superTypeSet = true; + } + return superType; + } + + @Override + public RiType exactType() { + if (Modifier.isFinal(accessFlags)) { + return this; + } + return null; + } + + @Override + public CiConstant getEncoding(Representation r) { + switch (r) { + case JavaClass: + return CiConstant.forObject(javaMirror); + case ObjectHub: + return CiConstant.forObject(this); + case StaticFields: + return CiConstant.forObject(javaMirror); + case TypeInfo: + return CiConstant.forObject(this); + default: + return null; + } + } + + @Override + public CiKind getRepresentationKind(Representation r) { + return CiKind.Object; + } + + @Override + public boolean hasFinalizableSubclass() { + return hasFinalizableSubclass; + } + + @Override + public boolean hasFinalizer() { + return hasFinalizer; + } + + @Override + public boolean hasSubclass() { + return hasSubclass; + } + + @Override + public boolean isArrayClass() { + return isArrayClass; + } + + @Override + public boolean isInitialized() { + return isInitialized; + } + + @Override + public boolean isInstance(CiConstant obj) { + return javaMirror.isInstance(obj); + } + + @Override + public boolean isInstanceClass() { + return isInstanceClass; + } + + @Override + public boolean isInterface() { + return isInterface; + } + + @Override + public boolean isResolved() { + return true; + } + + @Override + public boolean isSubtypeOf(RiType other) { + if (other instanceof HotSpotTypeResolved) { + return compiler.getVMEntries().RiType_isSubtypeOf(this, other); + } + // No resolved type is a subtype of an unresolved type. + return false; + } + + @Override + public CiKind kind() { + return CiKind.Object; + } + + @Override + public RiMethod resolveMethodImpl(RiMethod method) { + assert method instanceof HotSpotMethod; + return compiler.getVMEntries().RiType_resolveMethodImpl(this, method.name(), method.signature().asString()); + } + + @Override + public String toString() { + return "HotSpotType<" + simpleName + ", resolved>"; + } + + @Override + public RiConstantPool constantPool() { + // TODO: Implement constant pool without the need for VmId and cache the constant pool. + return compiler.getVMEntries().RiType_constantPool(this); + } + + @Override + public int instanceSize() { + return instanceSize; + } + + @Override + public RiField createRiField(String name, RiType type, int offset, int flags) { + RiField result = null; + + long id = offset + ((long) flags << 32); + + // (tw) Must cache the fields, because the local load elimination only works if the objects from two field lookups are equal. + if (fieldCache == null) { + fieldCache = new HashMap(8); + } else { + result = fieldCache.get(id); + } + + if (result == null) { + result = new HotSpotField(compiler, this, name, type, offset, flags); + fieldCache.put(id, result); + } else { + assert result.name().equals(name); + assert result.accessFlags() == flags; + } + + return result; + } + + @Override + public RiMethod uniqueConcreteMethod(RiMethod method) { + assert method instanceof HotSpotMethodResolved; + return ((HotSpotMethodResolved) method).uniqueConcreteMethod(); + } + +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotTypeUnresolved.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotTypeUnresolved.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.runtime; + +import com.sun.cri.ci.*; +import com.sun.cri.ri.*; + +/** + * Implementation of RiType for unresolved HotSpot classes. + */ +public class HotSpotTypeUnresolved extends HotSpotType { + + public final String simpleName; + public final int dimensions; + + /** + * Creates a new unresolved type for a specified type descriptor. + */ + public HotSpotTypeUnresolved(Compiler compiler, String name) { + super(compiler); + assert name.length() > 0 : "name cannot be empty"; + + int dimensions = 0; + // Decode name if necessary. + if (name.charAt(name.length() - 1) == ';') { + int startIndex = 0; + while (name.charAt(startIndex) == '[') { + startIndex++; + dimensions++; + } + assert name.charAt(startIndex) == 'L'; + this.simpleName = name.substring(startIndex + 1, name.length() - 1); + this.name = name; + } else { + this.simpleName = name; + this.name = getFullName(name, dimensions); + } + + this.dimensions = dimensions; + } + + public HotSpotTypeUnresolved(Compiler compiler, String name, int dimensions) { + super(compiler); + assert dimensions >= 0; + this.simpleName = name; + this.dimensions = dimensions; + this.name = getFullName(name, dimensions); + } + + private String getFullName(String name, int dimensions) { + StringBuilder str = new StringBuilder(); + for (int i = 0; i < dimensions; i++) { + str.append('['); + } + str.append('L').append(simpleName).append(';'); + return str.toString(); + } + + @Override + public RiType uniqueConcreteSubtype() { + throw unresolved("uniqueConcreteSubtype"); + } + + @Override + public boolean hasSubclass() { + throw unresolved("hasSubclass()"); + } + + @Override + public boolean hasFinalizer() { + throw unresolved("hasFinalizer()"); + } + + @Override + public boolean hasFinalizableSubclass() { + throw unresolved("hasFinalizableSubclass()"); + } + + @Override + public boolean isInterface() { + throw unresolved("isInterface()"); + } + + @Override + public boolean isArrayClass() { + return dimensions > 0; + } + + @Override + public boolean isInstanceClass() { + throw unresolved("isInstanceClass()"); + } + + @Override + public int accessFlags() { + throw unresolved("accessFlags()"); + } + + @Override + public boolean isResolved() { + return false; + } + + @Override + public boolean isInitialized() { + throw unresolved("isInitialized()"); + } + + @Override + public boolean isSubtypeOf(RiType other) { + throw unresolved("isSubtypeOf()"); + } + + @Override + public boolean isInstance(CiConstant obj) { + throw unresolved("isInstance()"); + } + + @Override + public RiType componentType() { + assert isArrayClass() : "no array class" + name(); + return new HotSpotTypeUnresolved(compiler, simpleName, dimensions - 1); + } + + @Override + public RiType exactType() { + throw unresolved("exactType()"); + } + + @Override + public RiType superType() { + throw unresolved("superType()"); + } + + @Override + public RiType arrayOf() { + return new HotSpotTypeUnresolved(compiler, simpleName, dimensions + 1); + } + + @Override + public RiMethod resolveMethodImpl(RiMethod method) { + throw unresolved("resolveMethodImpl()"); + } + + @Override + public CiKind kind() { + return CiKind.Object; + } + + private CiUnresolvedException unresolved(String operation) { + throw new CiUnresolvedException(operation + " not defined for unresolved class " + simpleName); + } + + @Override + public int hashCode() { + return simpleName.hashCode(); + } + + @Override + public boolean equals(Object o) { + return o == this; + } + + @Override + public String toString() { + return "HotSpotType<" + simpleName + ", unresolved>"; + } + + @Override + public CiConstant getEncoding(RiType.Representation r) { + throw unresolved("getEncoding()"); + } + + @Override + public CiKind getRepresentationKind(RiType.Representation r) { + return CiKind.Object; + } + + @Override + public RiMethod uniqueConcreteMethod(RiMethod method) { + throw unresolved("uniqueConcreteMethod"); + } + +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotVMConfig.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotVMConfig.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.runtime; + +import com.sun.cri.ci.*; + +/** + * Used to communicate configuration details, runtime offsets, etc. to c1x upon compileMethod. + */ +public final class HotSpotVMConfig extends CompilerObject { + + private HotSpotVMConfig() { + super(null); + } + + // os information, register layout, code generation, ... + public boolean windowsOs; + public int codeEntryAlignment; + public boolean verifyPointers; + public boolean useFastLocking; + public boolean useFastNewObjectArray; + public boolean useFastNewTypeArray; + + // offsets, ... + public int vmPageSize; + public int stackShadowPages; + public int hubOffset; + public int arrayLengthOffset; + public int klassStateOffset; + public int klassStateFullyInitialized; + public int[] arrayOffsets; + public int arrayClassElementOffset; + public int threadTlabTopOffset; + public int threadTlabEndOffset; + public int threadObjectOffset; + public int instanceHeaderPrototypeOffset; + public int threadExceptionOopOffset; + public int threadExceptionPcOffset; + public int threadMultiNewArrayStorage; + public long cardtableStartAddress; + public int cardtableShift; + public long safepointPollingAddress; + public int classMirrorOffset; + + // runtime stubs + public long debugStub; + public long instanceofStub; + public long newInstanceStub; + public long unresolvedNewInstanceStub; + public long newTypeArrayStub; + public long newObjectArrayStub; + public long newMultiArrayStub; + public long loadKlassStub; + public long accessFieldStub; + public long resolveStaticCallStub; + public long inlineCacheMissStub; + public long unwindExceptionStub; + public long handleExceptionStub; + public long handleDeoptStub; + public long monitorEnterStub; + public long monitorExitStub; + public long fastMonitorEnterStub; + public long fastMonitorExitStub; + public long verifyPointerStub; + + public void check() { + assert vmPageSize >= 16; + assert codeEntryAlignment > 0; + assert stackShadowPages > 0; + } + + public int getArrayOffset(CiKind kind) { + return arrayOffsets[getKindNumber(kind)]; + } + + private int getKindNumber(CiKind kind) { + if (kind == CiKind.Boolean) { + return 0; + } else if (kind == CiKind.Byte) { + return 1; + } else if (kind == CiKind.Short) { + return 2; + } else if (kind == CiKind.Char) { + return 3; + } else if (kind == CiKind.Int) { + return 4; + } else if (kind == CiKind.Float) { + return 5; + } else if (kind == CiKind.Long) { + return 6; + } else if (kind == CiKind.Double) { + return 7; + } else if (kind == CiKind.Object) { + return 8; + } else { + throw new RuntimeException(kind + " is not a Java kind"); + } + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotXirGenerator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotXirGenerator.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,1330 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.runtime; + +import static com.oracle.max.graal.runtime.TemplateFlag.*; +import static com.sun.cri.ci.CiCallingConvention.Type.*; + +import java.lang.reflect.*; +import java.util.*; +import java.util.concurrent.*; + +import com.oracle.max.asm.target.amd64.*; +import com.sun.cri.ci.*; +import com.sun.cri.ci.CiAddress.*; +import com.sun.cri.ci.CiRegister.*; +import com.sun.cri.ri.*; +import com.sun.cri.ri.RiType.*; +import com.sun.cri.xir.*; +import com.sun.cri.xir.CiXirAssembler.*; + +public class HotSpotXirGenerator implements RiXirGenerator { + + // this needs to correspond to c1x_CodeInstaller.hpp + // @formatter:off + private static final Integer MARK_VERIFIED_ENTRY = 0x0001; + private static final Integer MARK_UNVERIFIED_ENTRY = 0x0002; + private static final Integer MARK_OSR_ENTRY = 0x0003; + private static final Integer MARK_UNWIND_ENTRY = 0x0004; + private static final Integer MARK_EXCEPTION_HANDLER_ENTRY = 0x0005; + private static final Integer MARK_DEOPT_HANDLER_ENTRY = 0x0006; + + private static final Integer MARK_STATIC_CALL_STUB = 0x1000; + + private static final Integer MARK_INVOKE_INVALID = 0x2000; + private static final Integer MARK_INVOKEINTERFACE = 0x2001; + private static final Integer MARK_INVOKESTATIC = 0x2002; + private static final Integer MARK_INVOKESPECIAL = 0x2003; + private static final Integer MARK_INVOKEVIRTUAL = 0x2004; + + private static final Integer MARK_IMPLICIT_NULL = 0x3000; + + private static final Integer MARK_KLASS_PATCHING = 0x4000; + private static final Integer MARK_DUMMY_OOP_RELOCATION = 0x4001; + private static final Integer MARK_ACCESS_FIELD_PATCHING = 0x4002; + // @formatter:on + + private final HotSpotVMConfig config; + private final CiTarget target; + private final RiRegisterConfig registerConfig; + private final Compiler compiler; + + private CiXirAssembler globalAsm; + + public HotSpotXirGenerator(HotSpotVMConfig config, CiTarget target, RiRegisterConfig registerConfig, Compiler compiler) { + this.config = config; + this.target = target; + this.registerConfig = registerConfig; + this.compiler = compiler; + } + + private SimpleTemplates prologueTemplates = new SimpleTemplates(STATIC_METHOD) { + + @Override + protected XirTemplate create(CiXirAssembler asm, long flags) { + asm.restart(CiKind.Void); + XirOperand framePointer = asm.createRegisterTemp("frame pointer", CiKind.Word, AMD64.rbp); + XirOperand stackPointer = asm.createRegisterTemp("stack pointer", CiKind.Word, AMD64.rsp); + XirLabel unverifiedStub = null; + + asm.mark(MARK_OSR_ENTRY); + asm.mark(MARK_UNVERIFIED_ENTRY); + if (!is(STATIC_METHOD, flags)) { + unverifiedStub = asm.createOutOfLineLabel("unverified"); + + XirOperand temp = asm.createRegisterTemp("temp (r10)", CiKind.Word, AMD64.r10); + XirOperand cache = asm.createRegisterTemp("cache (rax)", CiKind.Word, AMD64.rax); + + CiCallingConvention conventions = registerConfig.getCallingConvention(JavaCallee, new CiKind[] {CiKind.Object}, target); + XirOperand receiver = asm.createRegisterTemp("receiver", CiKind.Word, conventions.locations[0].asRegister()); + + asm.pload(CiKind.Word, temp, receiver, asm.i(config.hubOffset), false); + asm.jneq(unverifiedStub, cache, temp); + } + asm.align(config.codeEntryAlignment); + asm.mark(MARK_VERIFIED_ENTRY); + asm.stackOverflowCheck(); + asm.push(framePointer); + asm.mov(framePointer, stackPointer); + asm.pushFrame(); + + // -- out of line ------------------------------------------------------- + XirOperand thread = asm.createRegisterTemp("thread", CiKind.Word, AMD64.r15); + XirOperand exceptionOop = asm.createTemp("exception oop", CiKind.Object); + XirLabel unwind = asm.createOutOfLineLabel("unwind"); + asm.bindOutOfLine(unwind); + + asm.mark(MARK_UNWIND_ENTRY); + + asm.pload(CiKind.Object, exceptionOop, thread, asm.i(config.threadExceptionOopOffset), false); + asm.pstore(CiKind.Object, thread, asm.i(config.threadExceptionOopOffset), asm.createConstant(CiConstant.NULL_OBJECT), false); + asm.pstore(CiKind.Long, thread, asm.i(config.threadExceptionPcOffset), asm.l(0), false); + + asm.callRuntime(config.unwindExceptionStub, null, exceptionOop); + asm.shouldNotReachHere(); + + asm.mark(MARK_EXCEPTION_HANDLER_ENTRY); + asm.callRuntime(config.handleExceptionStub, null); + asm.shouldNotReachHere(); + + asm.nop(1); + asm.mark(MARK_DEOPT_HANDLER_ENTRY); + asm.callRuntime(config.handleDeoptStub, null); + asm.shouldNotReachHere(); + + if (!is(STATIC_METHOD, flags)) { + asm.bindOutOfLine(unverifiedStub); + asm.jmpRuntime(config.inlineCacheMissStub); + } + + return asm.finishTemplate(is(STATIC_METHOD, flags) ? "static prologue" : "prologue"); + } + }; + + private SimpleTemplates epilogueTemplates = new SimpleTemplates(STATIC_METHOD, SYNCHRONIZED) { + + @Override + protected XirTemplate create(CiXirAssembler asm, long flags) { + asm.restart(CiKind.Void); + XirOperand framePointer = asm.createRegisterTemp("frame pointer", CiKind.Word, AMD64.rbp); + + asm.popFrame(); + asm.pop(framePointer); + + // TODO safepoint check + + return asm.finishTemplate("epilogue"); + } + }; + + private SimpleTemplates safepointTemplates = new SimpleTemplates() { + + @Override + protected XirTemplate create(CiXirAssembler asm, long flags) { + asm.restart(CiKind.Void); + + // XirOperand temp = asm.createRegister("temp", CiKind.Word, AMD64.rax); + // asm.pload(CiKind.Word, temp, asm.w(config.safepointPollingAddress), true); + + return asm.finishTemplate("safepoint"); + } + }; + + private SimpleTemplates exceptionObjectTemplates = new SimpleTemplates() { + + @Override + protected XirTemplate create(CiXirAssembler asm, long flags) { + XirOperand result = asm.restart(CiKind.Object); + XirOperand thread = asm.createRegisterTemp("thread", CiKind.Word, AMD64.r15); + + asm.pload(CiKind.Object, result, thread, asm.i(config.threadExceptionOopOffset), false); + asm.pstore(CiKind.Object, thread, asm.i(config.threadExceptionOopOffset), asm.o(null), false); + asm.pstore(CiKind.Long, thread, asm.i(config.threadExceptionPcOffset), asm.l(0), false); + + return asm.finishTemplate("exception object"); + } + }; + + private SimpleTemplates invokeInterfaceTemplates = new SimpleTemplates(NULL_CHECK) { + + @Override + protected XirTemplate create(CiXirAssembler asm, long flags) { + asm.restart(); + XirParameter receiver = asm.createInputParameter("receiver", CiKind.Object); + XirParameter addr = asm.createConstantInputParameter("addr", CiKind.Word); + XirOperand temp = asm.createRegisterTemp("temp", CiKind.Word, AMD64.rax); + + if (is(NULL_CHECK, flags)) { + asm.nop(1); + asm.mark(MARK_IMPLICIT_NULL); + asm.pload(CiKind.Word, temp, receiver, true); + } + asm.mark(MARK_INVOKEINTERFACE); + asm.mov(temp, asm.createConstant(CiConstant.forObject(HotSpotProxy.DUMMY_CONSTANT_OBJ))); + + return asm.finishTemplate(addr, "invokeinterface"); + } + }; + + private SimpleTemplates invokeVirtualTemplates = new SimpleTemplates(NULL_CHECK) { + + @Override + protected XirTemplate create(CiXirAssembler asm, long flags) { + asm.restart(); + XirParameter receiver = asm.createInputParameter("receiver", CiKind.Object); + XirParameter addr = asm.createConstantInputParameter("addr", CiKind.Word); + XirOperand temp = asm.createRegisterTemp("temp", CiKind.Word, AMD64.rax); + + if (is(NULL_CHECK, flags)) { + asm.nop(1); + asm.mark(MARK_IMPLICIT_NULL); + asm.pload(CiKind.Word, temp, receiver, true); + } + asm.mark(MARK_INVOKEVIRTUAL); + asm.mov(temp, asm.createConstant(CiConstant.forObject(HotSpotProxy.DUMMY_CONSTANT_OBJ))); + + return asm.finishTemplate(addr, "invokevirtual"); + } + }; + + private SimpleTemplates invokeSpecialTemplates = new SimpleTemplates(NULL_CHECK) { + + @Override + protected XirTemplate create(CiXirAssembler asm, long flags) { + asm.restart(); + XirParameter receiver = asm.createInputParameter("receiver", CiKind.Object); + XirParameter addr = asm.createConstantInputParameter("addr", CiKind.Word); + XirOperand temp = asm.createRegisterTemp("temp", CiKind.Word, AMD64.rax); + XirLabel stub = asm.createOutOfLineLabel("call stub"); + + if (is(NULL_CHECK, flags)) { + asm.nop(1); + asm.mark(MARK_IMPLICIT_NULL); + asm.pload(CiKind.Word, temp, receiver, true); + } + asm.mark(MARK_INVOKESPECIAL); + + // -- out of line ------------------------------------------------------- + asm.bindOutOfLine(stub); + XirOperand method = asm.createRegisterTemp("method", CiKind.Word, AMD64.rbx); + asm.mark(MARK_STATIC_CALL_STUB, XirMark.CALLSITE); + asm.mov(method, asm.w(0L)); + XirLabel dummy = asm.createOutOfLineLabel("dummy"); + asm.jmp(dummy); + asm.bindOutOfLine(dummy); + + return asm.finishTemplate(addr, "invokespecial"); + } + }; + + private SimpleTemplates invokeStaticTemplates = new SimpleTemplates() { + + @Override + protected XirTemplate create(CiXirAssembler asm, long flags) { + asm.restart(); + XirParameter addr = asm.createConstantInputParameter("addr", CiKind.Word); + + XirLabel stub = asm.createOutOfLineLabel("call stub"); + asm.mark(MARK_INVOKESTATIC); + + // -- out of line ------------------------------------------------------- + asm.bindOutOfLine(stub); + XirOperand method = asm.createRegisterTemp("method", CiKind.Word, AMD64.rbx); + asm.mark(MARK_STATIC_CALL_STUB, XirMark.CALLSITE); + asm.mov(method, asm.w(0L)); + XirLabel dummy = asm.createOutOfLineLabel("dummy"); + asm.jmp(dummy); + asm.bindOutOfLine(dummy); + + return asm.finishTemplate(addr, "invokestatic"); + } + }; + + private SimpleTemplates monitorEnterTemplates = new SimpleTemplates(NULL_CHECK) { + + @Override + protected XirTemplate create(CiXirAssembler asm, long flags) { + asm.restart(CiKind.Void); + XirParameter object = asm.createInputParameter("object", CiKind.Object); + XirParameter lock = asm.createInputParameter("lock", CiKind.Word); + + if (is(NULL_CHECK, flags)) { + asm.nop(1); + asm.mark(MARK_IMPLICIT_NULL); + asm.pload(CiKind.Word, asm.createTemp("temp", CiKind.Word), object, true); + } + + + // (tw) It is important to use for this runtime call the debug info AFTER the monitor enter. Otherwise the monitor object + // is not correctly garbage collected. + final boolean useInfoAfter = true; + + if (config.useFastLocking) { + useRegisters(asm, AMD64.rax, AMD64.rbx); + useRegisters(asm, getGeneralParameterRegister(0)); + useRegisters(asm, getGeneralParameterRegister(1)); + asm.callRuntime(config.fastMonitorEnterStub, null, useInfoAfter, object, lock); + } else { + asm.reserveOutgoingStack(target.wordSize * 2); + asm.pstore(CiKind.Object, asm.createRegister("rsp", CiKind.Word, AMD64.RSP.asRegister()), asm.i(target.wordSize), object, false); + asm.pstore(CiKind.Word, asm.createRegister("rsp", CiKind.Word, AMD64.RSP.asRegister()), asm.i(0), lock, false); + asm.callRuntime(config.monitorEnterStub, null, useInfoAfter); + } + + return asm.finishTemplate("monitorEnter"); + } + }; + + private CiRegister getGeneralParameterRegister(int index) { + return registerConfig.getCallingConventionRegisters(CiCallingConvention.Type.RuntimeCall, RegisterFlag.CPU)[index]; + } + + private SimpleTemplates monitorExitTemplates = new SimpleTemplates(NULL_CHECK) { + + @Override + protected XirTemplate create(CiXirAssembler asm, long flags) { + asm.restart(CiKind.Void); + XirParameter object = asm.createInputParameter("object", CiKind.Object); + XirParameter lock = asm.createInputParameter("lock", CiKind.Word); + + if (config.useFastLocking) { + useRegisters(asm, AMD64.rax, AMD64.rbx); + useRegisters(asm, getGeneralParameterRegister(0)); + useRegisters(asm, getGeneralParameterRegister(1)); + asm.callRuntime(config.fastMonitorExitStub, null, object, lock); + } else { + asm.reserveOutgoingStack(target.wordSize); + asm.pstore(CiKind.Word, asm.createRegister("rsp", CiKind.Word, AMD64.RSP.asRegister()), asm.i(0), lock, false); + asm.callRuntime(config.monitorExitStub, null); + } + + return asm.finishTemplate("monitorExit"); + } + }; + + private KindTemplates getFieldTemplates = new KindTemplates(NULL_CHECK) { + + @Override + protected XirTemplate create(CiXirAssembler asm, long flags, CiKind kind) { + XirOperand result = asm.restart(kind); + XirParameter object = asm.createInputParameter("object", CiKind.Object); + + XirParameter fieldOffset = asm.createConstantInputParameter("fieldOffset", CiKind.Int); + if (is(NULL_CHECK, flags)) { + asm.nop(1); + asm.mark(MARK_IMPLICIT_NULL); + } + asm.pload(kind, result, object, fieldOffset, is(NULL_CHECK, flags)); + return asm.finishTemplate("getfield<" + kind + ">"); + } + }; + + private KindTemplates writeBarrierTemplate = new KindTemplates() { + + @Override + protected XirTemplate create(CiXirAssembler asm, long flags, CiKind kind) { + asm.restart(CiKind.Void); + XirParameter object = asm.createInputParameter("object", CiKind.Object); + + // Need temp operand, because the write barrier destroys the object pointer. + XirOperand temp = asm.createTemp("temp", CiKind.Object); + asm.mov(temp, object); + + writeBarrier(asm, temp); + return asm.finishTemplate("writeBarrier"); + } + }; + + private KindTemplates putFieldTemplates = new KindTemplates(WRITE_BARRIER, NULL_CHECK) { + + @Override + protected XirTemplate create(CiXirAssembler asm, long flags, CiKind kind) { + asm.restart(CiKind.Void); + XirParameter object = asm.createInputParameter("object", CiKind.Object); + XirParameter value = asm.createInputParameter("value", kind); + XirParameter fieldOffset = asm.createConstantInputParameter("fieldOffset", CiKind.Int); + if (kind == CiKind.Object) { + verifyPointer(asm, value); + } + if (is(NULL_CHECK, flags)) { + asm.nop(1); + asm.mark(MARK_IMPLICIT_NULL); + } + asm.pstore(kind, object, fieldOffset, value, is(NULL_CHECK, flags)); + if (is(WRITE_BARRIER, flags) && kind == CiKind.Object) { + XirOperand temp = asm.createTemp("temp", CiKind.Word); + asm.mov(temp, object); + writeBarrier(asm, temp); + } + return asm.finishTemplate("putfield<" + kind + ">"); + } + }; + + private final IndexTemplates newInstanceTemplates = new IndexTemplates() { + + @Override + protected XirTemplate create(CiXirAssembler asm, long flags, int size) { + XirOperand result = asm.restart(CiKind.Word); + XirOperand type = asm.createInputParameter("type", CiKind.Object); + + XirOperand temp1 = asm.createRegisterTemp("temp1", CiKind.Word, AMD64.rcx); + XirOperand temp2 = asm.createRegisterTemp("temp2", CiKind.Word, AMD64.rbx); + XirOperand temp2i = asm.createRegisterTemp("temp2i", CiKind.Int, AMD64.rbx); + useRegisters(asm, AMD64.rsi); + XirLabel tlabFull = asm.createOutOfLineLabel("tlab full"); + XirLabel resume = asm.createInlineLabel("resume"); + + // check if the class is already initialized + asm.pload(CiKind.Int, temp2i, type, asm.i(config.klassStateOffset), false); + asm.jneq(tlabFull, temp2i, asm.i(config.klassStateFullyInitialized)); + + XirOperand thread = asm.createRegisterTemp("thread", CiKind.Word, AMD64.r15); + asm.pload(CiKind.Word, result, thread, asm.i(config.threadTlabTopOffset), false); + asm.add(temp1, result, asm.w(size)); + asm.pload(CiKind.Word, temp2, thread, asm.i(config.threadTlabEndOffset), false); + + asm.jgt(tlabFull, temp1, temp2); + asm.pstore(CiKind.Word, thread, asm.i(config.threadTlabTopOffset), temp1, false); + + asm.bindInline(resume); + + asm.pload(CiKind.Word, temp1, type, asm.i(config.instanceHeaderPrototypeOffset), false); + asm.pstore(CiKind.Word, result, temp1, false); + asm.pstore(CiKind.Object, result, asm.i(config.hubOffset), type, false); + + if (size > 2 * target.wordSize) { + asm.mov(temp1, asm.w(0)); + for (int offset = 2 * target.wordSize; offset < size; offset += target.wordSize) { + asm.pstore(CiKind.Word, result, asm.i(offset), temp1, false); + } + } + + // -- out of line ------------------------------------------------------- + asm.bindOutOfLine(tlabFull); + XirOperand arg = asm.createRegisterTemp("runtime call argument", CiKind.Object, AMD64.rdx); + asm.mov(arg, type); + useRegisters(asm, AMD64.rax); + asm.callRuntime(config.newInstanceStub, result); + asm.jmp(resume); + + return asm.finishTemplate("new instance"); + } + }; + + private SimpleTemplates newObjectArrayCloneTemplates = new SimpleTemplates() { + + @Override + protected XirTemplate create(CiXirAssembler asm, long flags) { + XirOperand result = asm.restart(CiKind.Object); + XirParameter lengthParam = asm.createInputParameter("length", CiKind.Int, true); + XirParameter src = asm.createInputParameter("src", CiKind.Object); + + // Set up length and hub. + XirOperand length = asm.createRegisterTemp("length", CiKind.Int, AMD64.rbx); + XirOperand hub = asm.createRegisterTemp("hub", CiKind.Object, AMD64.rdx); + asm.pload(CiKind.Object, hub, src, asm.i(config.hubOffset), false); + asm.mov(length, lengthParam); + + useRegisters(asm, AMD64.rsi, AMD64.rcx, AMD64.rdi, AMD64.rax); + asm.callRuntime(config.newObjectArrayStub, result); + return asm.finishTemplate("objectArrayClone"); + } + }; + + private SimpleTemplates newObjectArrayTemplates = new SimpleTemplates() { + + @Override + protected XirTemplate create(CiXirAssembler asm, long flags) { + emitNewTypeArray(asm, flags, CiKind.Object, config.useFastNewObjectArray, config.newObjectArrayStub); + return asm.finishTemplate("newObjectArray"); + } + }; + + private void emitNewTypeArray(CiXirAssembler asm, long flags, CiKind kind, boolean useFast, long slowPathStub) { + XirOperand result = asm.restart(CiKind.Word); + + XirParameter lengthParam = asm.createInputParameter("length", CiKind.Int, true); + + XirOperand length = asm.createRegisterTemp("length", CiKind.Int, AMD64.rbx); + XirOperand hub = asm.createRegisterTemp("hub", CiKind.Object, AMD64.rdx); + + // Registers rsi, rcx, rdi, and rax are needed by the runtime call. + // Hub needs to be on rdx, length on rbx. + XirOperand temp1 = asm.createRegisterTemp("temp1", CiKind.Word, AMD64.rcx); + XirOperand temp2 = asm.createRegisterTemp("temp2", CiKind.Word, AMD64.rax); + XirOperand temp3 = asm.createRegisterTemp("temp3", CiKind.Word, AMD64.rdi); + XirOperand size = asm.createRegisterTemp("size", CiKind.Int, AMD64.rsi); + + asm.mov(hub, asm.createConstantInputParameter("hub", CiKind.Object)); + asm.mov(length, lengthParam); + + if (useFast) { + + XirLabel slowPath = asm.createOutOfLineLabel("slowPath"); + + XirLabel done = asm.createInlineLabel("done"); + + // Check for negative array size. + // TODO: Also check for upper bound + asm.jlt(slowPath, length, asm.i(0)); + + final int aligning = target.wordSize; + final int arrayLengthOffset = target.wordSize * 2; + final int arrayElementOffset = config.getArrayOffset(kind); + + // Calculate aligned size + asm.mov(size, length); + int scale = CiUtil.log2(kind.sizeInBytes(target.wordSize)); + if (scale != 0) { + asm.shl(size, size, asm.i(scale)); + } + asm.add(size, size, asm.i(arrayElementOffset + aligning - 1)); + long mask = 0xFFFFFFFFL; + mask <<= CiUtil.log2(aligning); + asm.and(size, size, asm.i((int) mask)); + + // Try tlab allocation + XirOperand thread = asm.createRegisterTemp("thread", CiKind.Word, AMD64.r15); + asm.pload(CiKind.Word, result, thread, asm.i(config.threadTlabTopOffset), false); + asm.add(temp1, result, size); + asm.pload(CiKind.Word, temp2, thread, asm.i(config.threadTlabEndOffset), false); + asm.jgt(slowPath, temp1, temp2); + asm.pstore(CiKind.Word, thread, asm.i(config.threadTlabTopOffset), temp1, false); + + // Now the new object is in result, store mark word and klass + asm.pload(CiKind.Word, temp1, hub, asm.i(config.instanceHeaderPrototypeOffset), false); + asm.pstore(CiKind.Word, result, temp1, false); + asm.pstore(CiKind.Object, result, asm.i(config.hubOffset), hub, false); + + // Store array length + asm.pstore(CiKind.Int, result, asm.i(arrayLengthOffset), length, false); + + // Initialize with 0 + XirLabel top = asm.createInlineLabel("top"); + asm.sub(size, size, asm.i(arrayElementOffset)); + asm.shr(size, size, asm.i(Scale.Times8.log2)); + asm.jeq(done, size, asm.i(0)); + asm.xor(temp3, temp3, temp3); + asm.bindInline(top); + asm.pstore(CiKind.Word, result, size, temp3, arrayElementOffset - target.wordSize, Scale.Times8, false); + asm.decAndJumpNotZero(top, size); + + asm.bindInline(done); + + // Slow path + asm.bindOutOfLine(slowPath); + asm.callRuntime(slowPathStub, result); + asm.jmp(done); + } else { + asm.callRuntime(slowPathStub, result); + } + } + + private KindTemplates newTypeArrayTemplates = new KindTemplates() { + @Override + protected XirTemplate create(CiXirAssembler asm, long flags, CiKind kind) { + emitNewTypeArray(asm, flags, kind, config.useFastNewTypeArray, config.newTypeArrayStub); + return asm.finishTemplate("newTypeArray<" + kind.toString() + ">"); + } + }; + + private final IndexTemplates multiNewArrayTemplate = new IndexTemplates() { + + @Override + protected XirTemplate create(CiXirAssembler asm, long flags, int dimensions) { + XirOperand result = asm.restart(CiKind.Object); + + XirOperand hub = asm.createRegisterTemp("hub", CiKind.Object, AMD64.rax); + XirOperand rank = asm.createRegisterTemp("rank", CiKind.Int, AMD64.rbx); + XirOperand sizes = asm.createRegisterTemp("sizes", CiKind.Long, AMD64.rcx); + XirOperand thread = asm.createRegisterTemp("thread", CiKind.Long, AMD64.r15); + asm.add(sizes, thread, asm.l(config.threadMultiNewArrayStorage)); + for (int i = 0; i < dimensions; i++) { + XirParameter length = asm.createInputParameter("length" + i, CiKind.Int, true); + asm.pstore(CiKind.Int, sizes, asm.i(i * target.sizeInBytes(CiKind.Int)), length, false); + } + + asm.mov(hub, asm.createConstantInputParameter("hub", CiKind.Object)); + + asm.mov(rank, asm.i(dimensions)); + useRegisters(asm, AMD64.rax); + asm.callRuntime(config.newMultiArrayStub, result); + return asm.finishTemplate("multiNewArray" + dimensions); + } + }; + + private SimpleTemplates checkCastTemplates = new SimpleTemplates(NULL_CHECK) { + + @Override + protected XirTemplate create(CiXirAssembler asm, long flags) { + asm.restart(); + XirParameter object = asm.createInputParameter("object", CiKind.Object); + final XirOperand hub; + hub = asm.createConstantInputParameter("hub", CiKind.Object); + + XirOperand objHub = asm.createTemp("objHub", CiKind.Object); + + XirLabel end = asm.createInlineLabel("end"); + XirLabel slowPath = asm.createOutOfLineLabel("slow path"); + + if (is(NULL_CHECK, flags)) { + // null can be cast to anything + asm.jeq(end, object, asm.o(null)); + } + + asm.pload(CiKind.Object, objHub, object, asm.i(config.hubOffset), false); + // if we get an exact match: succeed immediately + asm.jneq(slowPath, objHub, hub); + asm.bindInline(end); + + // -- out of line ------------------------------------------------------- + asm.bindOutOfLine(slowPath); + checkSubtype(asm, objHub, objHub, hub); + asm.jneq(end, objHub, asm.o(null)); + XirOperand scratch = asm.createRegisterTemp("scratch", CiKind.Object, AMD64.r10); + asm.mov(scratch, object); + + asm.callRuntime(CiRuntimeCall.Deoptimize, null); + asm.shouldNotReachHere(); + + return asm.finishTemplate(object, "instanceof"); + } + }; + + private SimpleTemplates instanceOfTemplates = new SimpleTemplates(NULL_CHECK) { + + @Override + protected XirTemplate create(CiXirAssembler asm, long flags) { + XirOperand result = asm.restart(CiKind.Boolean); + XirParameter object = asm.createInputParameter("object", CiKind.Object); + final XirOperand hub; + hub = asm.createConstantInputParameter("hub", CiKind.Object); + + XirOperand objHub = asm.createTemp("objHub", CiKind.Object); + + XirLabel end = asm.createInlineLabel("end"); + XirLabel slowPath = asm.createOutOfLineLabel("slow path"); + + if (is(NULL_CHECK, flags)) { + // null isn't "instanceof" anything + asm.mov(result, asm.b(false)); + asm.jeq(end, object, asm.o(null)); + } + + asm.pload(CiKind.Object, objHub, object, asm.i(config.hubOffset), false); + // if we get an exact match: succeed immediately + asm.mov(result, asm.b(true)); + asm.jneq(slowPath, objHub, hub); + asm.bindInline(end); + + // -- out of line ------------------------------------------------------- + asm.bindOutOfLine(slowPath); + checkSubtype(asm, result, objHub, hub); + asm.jmp(end); + + return asm.finishTemplate("instanceof"); + } + }; + + private XirOperand genArrayLength(CiXirAssembler asm, XirOperand array, boolean implicitNullException) { + XirOperand length = asm.createTemp("length", CiKind.Int); + genArrayLength(asm, length, array, implicitNullException); + return length; + } + + private void genArrayLength(CiXirAssembler asm, XirOperand length, XirOperand array, boolean implicitNullException) { + if (implicitNullException) { + asm.nop(1); + asm.mark(MARK_IMPLICIT_NULL); + } + asm.pload(CiKind.Int, length, array, asm.i(config.arrayLengthOffset), implicitNullException); + } + + private KindTemplates arrayLoadTemplates = new KindTemplates(NULL_CHECK, READ_BARRIER, BOUNDS_CHECK, GIVEN_LENGTH) { + + @Override + protected XirTemplate create(CiXirAssembler asm, long flags, CiKind kind) { + XirOperand result = asm.restart(kind); + XirParameter array = asm.createInputParameter("array", CiKind.Object); + XirParameter index = asm.createInputParameter("index", CiKind.Int, true); + XirLabel failBoundsCheck = null; + // if the length is known the array cannot be null + boolean implicitNullException = is(NULL_CHECK, flags); + + if (is(BOUNDS_CHECK, flags)) { + // load the array length and check the index + failBoundsCheck = asm.createOutOfLineLabel("failBoundsCheck"); + XirOperand length; + if (is(GIVEN_LENGTH, flags)) { + length = asm.createInputParameter("length", CiKind.Int, true); + } else { + length = genArrayLength(asm, array, implicitNullException); + } + asm.jugteq(failBoundsCheck, index, length); + implicitNullException = false; + } + int elemSize = target.sizeInBytes(kind); + if (implicitNullException) { + asm.nop(1); + asm.mark(MARK_IMPLICIT_NULL); + } + asm.pload(kind, result, array, index, config.getArrayOffset(kind), Scale.fromInt(elemSize), implicitNullException); + if (is(BOUNDS_CHECK, flags)) { + asm.bindOutOfLine(failBoundsCheck); + asm.callRuntime(CiRuntimeCall.Deoptimize, null); + asm.shouldNotReachHere(); + } + return asm.finishTemplate("arrayload<" + kind + ">"); + } + }; + + private SimpleTemplates getClassTemplates = new SimpleTemplates() { + @Override + protected XirTemplate create(CiXirAssembler asm, long flags) { + XirOperand result = asm.restart(CiKind.Object); + XirOperand object = asm.createInputParameter("object", CiKind.Object); + if (is(NULL_CHECK, flags)) { + asm.nop(1); + } + asm.pload(CiKind.Object, result, object, asm.i(config.hubOffset), is(NULL_CHECK, flags)); + asm.pload(CiKind.Object, result, result, asm.i(config.classMirrorOffset), false); + return asm.finishTemplate("currentThread"); + } + }; + + private SimpleTemplates currentThreadTemplates = new SimpleTemplates() { + @Override + protected XirTemplate create(CiXirAssembler asm, long flags) { + XirOperand result = asm.restart(CiKind.Object); + XirOperand thread = asm.createRegisterTemp("thread", CiKind.Word, AMD64.r15); + asm.pload(CiKind.Object, result, thread, asm.i(config.threadObjectOffset), false); + return asm.finishTemplate("currentThread"); + } + }; + + @Override + public XirSnippet genCurrentThread(XirSite site) { + return new XirSnippet(currentThreadTemplates.get(site)); + } + + @Override + public XirSnippet genGetClass(XirSite site, XirArgument object) { + return new XirSnippet(getClassTemplates.get(site), object); + } + + private KindTemplates arrayCopyTemplates = new KindTemplates() { + + @Override + protected XirTemplate create(CiXirAssembler asm, long flags, CiKind kind) { + asm.restart(CiKind.Void); + XirParameter src = asm.createInputParameter("src", CiKind.Object); + XirParameter srcPos = asm.createInputParameter("srcPos", CiKind.Int, true); + XirParameter dest = asm.createInputParameter("dest", CiKind.Object); + XirParameter destPos = asm.createInputParameter("destPos", CiKind.Int, true); + XirParameter length = asm.createInputParameter("length", CiKind.Int, true); + + XirOperand tempSrc = asm.createTemp("tempSrc", CiKind.Word); + XirOperand tempDest = asm.createTemp("tempDest", CiKind.Word); + XirOperand lengthOperand = asm.createRegisterTemp("lengthOperand", CiKind.Int, AMD64.rax); + + XirOperand compHub = null; + XirOperand valueHub = null; + XirOperand temp = null; + XirLabel store = null; + XirLabel slowStoreCheck = null; + + if (is(STORE_CHECK, flags) && kind == CiKind.Object) { + valueHub = asm.createRegisterTemp("valueHub", CiKind.Word, AMD64.rdi); + compHub = asm.createRegisterTemp("compHub", CiKind.Word, AMD64.rsi); + temp = asm.createRegisterTemp("temp", CiKind.Word, AMD64.r10); + } + + // Calculate the factor for the repeat move instruction. + int elementSize = kind.sizeInBytes(target.wordSize); + int factor; + boolean wordSize; + if (elementSize >= target.wordSize) { + assert elementSize % target.wordSize == 0; + wordSize = true; + factor = elementSize / target.wordSize; + } else { + factor = elementSize; + wordSize = false; + } + + // Adjust the length if the factor is not 1. + if (factor != 1) { + asm.shl(lengthOperand, length, asm.i(CiUtil.log2(factor))); + } else { + asm.mov(lengthOperand, length); + } + + // Set the start and the end pointer. + asm.lea(tempSrc, src, srcPos, config.getArrayOffset(kind), Scale.fromInt(elementSize)); + asm.lea(tempDest, dest, destPos, config.getArrayOffset(kind), Scale.fromInt(elementSize)); + + XirLabel reverse = null; + XirLabel normal = null; + + if (is(STORE_CHECK, flags)) { + reverse = asm.createInlineLabel("reverse"); + asm.jneq(reverse, src, dest); + } + + if (!is(STORE_CHECK, flags) && !is(INPUTS_DIFFERENT, flags) && !is(INPUTS_SAME, flags)) { + normal = asm.createInlineLabel("normal"); + asm.jneq(normal, src, dest); + } + + if (!is(INPUTS_DIFFERENT, flags)) { + if (reverse == null) { + reverse = asm.createInlineLabel("reverse"); + } + asm.jlt(reverse, srcPos, destPos); + } + + if (!is(STORE_CHECK, flags) && !is(INPUTS_DIFFERENT, flags) && !is(INPUTS_SAME, flags)) { + asm.bindInline(normal); + } + + // Everything set up => repeat mov. + if (wordSize) { + asm.repmov(tempSrc, tempDest, lengthOperand); + } else { + asm.repmovb(tempSrc, tempDest, lengthOperand); + } + + if (!is(INPUTS_DIFFERENT, flags) || is(STORE_CHECK, flags)) { + + XirLabel end = asm.createInlineLabel("end"); + asm.jmp(end); + + // Implement reverse copy, because srcPos < destPos and src == dest. + asm.bindInline(reverse); + + if (is(STORE_CHECK, flags)) { + asm.pload(CiKind.Object, compHub, dest, asm.i(config.hubOffset), false); + asm.pload(CiKind.Object, compHub, compHub, asm.i(config.arrayClassElementOffset), false); + } + + CiKind copyKind = wordSize ? CiKind.Object : CiKind.Byte; + XirOperand tempValue = asm.createTemp("tempValue", copyKind); + XirLabel start = asm.createInlineLabel("start"); + asm.bindInline(start); + asm.sub(lengthOperand, lengthOperand, asm.i(1)); + asm.jlt(end, lengthOperand, asm.i(0)); + + Scale scale = wordSize ? Scale.fromInt(target.wordSize) : Scale.Times1; + asm.pload(copyKind, tempValue, tempSrc, lengthOperand, 0, scale, false); + + if (is(STORE_CHECK, flags)) { + slowStoreCheck = asm.createOutOfLineLabel("slowStoreCheck"); + store = asm.createInlineLabel("store"); + asm.jeq(store, tempValue, asm.o(null)); // first check if value is null + asm.pload(CiKind.Object, valueHub, tempValue, asm.i(config.hubOffset), false); + asm.jneq(slowStoreCheck, compHub, valueHub); // then check component hub matches value hub + asm.bindInline(store); + } + + asm.pstore(copyKind, tempDest, lengthOperand, tempValue, 0, scale, false); + + asm.jmp(start); + asm.bindInline(end); + } + + if (kind == CiKind.Object) { + // Do write barriers + asm.lea(tempDest, dest, destPos, config.getArrayOffset(kind), Scale.fromInt(elementSize)); + asm.shr(tempDest, tempDest, asm.i(config.cardtableShift)); + asm.pstore(CiKind.Boolean, asm.w(config.cardtableStartAddress), tempDest, asm.b(false), false); + + XirOperand tempDestEnd = tempSrc; // Reuse src temp + asm.lea(tempDestEnd, dest, destPos, config.getArrayOffset(kind), Scale.fromInt(elementSize)); + asm.add(tempDestEnd, tempDestEnd, length); + asm.shr(tempDestEnd, tempDestEnd, asm.i(config.cardtableShift)); + + // Jump to out-of-line write barrier loop if the array is big. + XirLabel writeBarrierLoop = asm.createOutOfLineLabel("writeBarrierLoop"); + asm.jneq(writeBarrierLoop, tempDest, tempSrc); + XirLabel back = asm.createInlineLabel("back"); + asm.bindInline(back); + + asm.bindOutOfLine(writeBarrierLoop); + asm.pstore(CiKind.Boolean, asm.w(config.cardtableStartAddress), tempDestEnd, asm.b(false), false); + asm.sub(tempDestEnd, tempDestEnd, asm.i(1)); + asm.jneq(writeBarrierLoop, tempDestEnd, tempDest); + asm.jmp(back); + } + + if (is(STORE_CHECK, flags)) { + assert kind == CiKind.Object; + useRegisters(asm, AMD64.rax); + asm.bindOutOfLine(slowStoreCheck); + checkSubtype(asm, temp, valueHub, compHub); + asm.jneq(store, temp, asm.w(0)); + XirOperand scratch = asm.createRegisterTemp("scratch", CiKind.Object, AMD64.r10); + asm.mov(scratch, valueHub); + asm.callRuntime(CiRuntimeCall.Deoptimize, null); + asm.jmp(store); + } + + return asm.finishTemplate("arraycopy<" + kind + ">"); + } + }; + + private KindTemplates arrayStoreTemplates = new KindTemplates(NULL_CHECK, WRITE_BARRIER, BOUNDS_CHECK, STORE_CHECK, GIVEN_LENGTH) { + + @Override + protected XirTemplate create(CiXirAssembler asm, long flags, CiKind kind) { + asm.restart(CiKind.Void); + XirParameter array = asm.createInputParameter("array", CiKind.Object); + XirParameter index = asm.createInputParameter("index", CiKind.Int, true); + XirParameter value = asm.createInputParameter("value", kind, kind != CiKind.Object); + XirOperand temp = asm.createTemp("temp", CiKind.Word); + XirOperand valueHub = null; + XirOperand compHub = null; + XirLabel store = asm.createInlineLabel("store"); + XirLabel failBoundsCheck = null; + XirLabel slowStoreCheck = null; + // if the length is known the array cannot be null + boolean implicitNullException = is(NULL_CHECK, flags); + + if (is(BOUNDS_CHECK, flags)) { + // load the array length and check the index + failBoundsCheck = asm.createOutOfLineLabel("failBoundsCheck"); + XirOperand length; + if (is(GIVEN_LENGTH, flags)) { + length = asm.createInputParameter("length", CiKind.Int); + } else { + length = asm.createTemp("length", CiKind.Int); + if (implicitNullException) { + asm.nop(1); + asm.mark(MARK_IMPLICIT_NULL); + } + asm.pload(CiKind.Int, length, array, asm.i(config.arrayLengthOffset), implicitNullException); + implicitNullException = false; + } + asm.jugteq(failBoundsCheck, index, length); + + } + if (is(STORE_CHECK, flags) && kind == CiKind.Object) { + slowStoreCheck = asm.createOutOfLineLabel("slowStoreCheck"); + asm.jeq(store, value, asm.o(null)); // first check if value is null + valueHub = asm.createTemp("valueHub", CiKind.Object); + compHub = asm.createTemp("compHub", CiKind.Object); + if (implicitNullException) { + asm.nop(1); + asm.mark(MARK_IMPLICIT_NULL); + } + asm.pload(CiKind.Object, compHub, array, asm.i(config.hubOffset), implicitNullException); + asm.pload(CiKind.Object, compHub, compHub, asm.i(config.arrayClassElementOffset), false); + asm.pload(CiKind.Object, valueHub, value, asm.i(config.hubOffset), false); + asm.jneq(slowStoreCheck, compHub, valueHub); // then check component hub matches value hub + + implicitNullException = false; + } + asm.bindInline(store); + int elemSize = target.sizeInBytes(kind); + + if (implicitNullException) { + asm.nop(1); + asm.mark(MARK_IMPLICIT_NULL); + } + int disp = config.getArrayOffset(kind); + Scale scale = Scale.fromInt(elemSize); + if (kind == CiKind.Object) { + verifyPointer(asm, value); + } + if (is(WRITE_BARRIER, flags) && kind == CiKind.Object) { + asm.lea(temp, array, index, disp, scale); + asm.pstore(kind, temp, value, implicitNullException); + writeBarrier(asm, temp); + } else { + asm.pstore(kind, array, index, value, disp, scale, implicitNullException); + } + + // -- out of line ------------------------------------------------------- + if (is(BOUNDS_CHECK, flags)) { + asm.bindOutOfLine(failBoundsCheck); + asm.callRuntime(CiRuntimeCall.Deoptimize, null); + asm.shouldNotReachHere(); + } + if (is(STORE_CHECK, flags) && kind == CiKind.Object) { + useRegisters(asm, AMD64.rax); + asm.bindOutOfLine(slowStoreCheck); + checkSubtype(asm, temp, valueHub, compHub); + asm.jneq(store, temp, asm.w(0)); + XirOperand scratch = asm.createRegisterTemp("scratch", CiKind.Object, AMD64.r10); + asm.mov(scratch, valueHub); + asm.callRuntime(CiRuntimeCall.Deoptimize, null); + asm.shouldNotReachHere(); + } + return asm.finishTemplate("arraystore<" + kind + ">"); + } + }; + + private SimpleTemplates arrayLengthTemplates = new SimpleTemplates(NULL_CHECK) { + + @Override + protected XirTemplate create(CiXirAssembler asm, long flags) { + XirOperand result = asm.restart(CiKind.Int); + XirParameter object = asm.createInputParameter("object", CiKind.Object); + if (is(NULL_CHECK, flags)) { + asm.nop(1); + asm.mark(MARK_IMPLICIT_NULL); + } + verifyPointer(asm, object); + asm.pload(CiKind.Int, result, object, asm.i(config.arrayLengthOffset), true); + return asm.finishTemplate("arrayLength"); + } + }; + + @Override + public XirSnippet genPrologue(XirSite site, RiMethod method) { + boolean staticMethod = Modifier.isStatic(method.accessFlags()); + return new XirSnippet(staticMethod ? prologueTemplates.get(site, STATIC_METHOD) : prologueTemplates.get(site)); + } + + @Override + public XirSnippet genEpilogue(XirSite site, RiMethod method) { + return new XirSnippet(epilogueTemplates.get(site)); + } + + @Override + public XirSnippet genSafepoint(XirSite site) { + return new XirSnippet(safepointTemplates.get(site)); + } + + @Override + public XirSnippet genExceptionObject(XirSite site) { + return new XirSnippet(exceptionObjectTemplates.get(site)); + } + + @Override + public XirSnippet genResolveClass(XirSite site, RiType type, Representation rep) { + throw new CiBailout("Xir ResolveClass not available"); + } + + @Override + public XirSnippet genIntrinsic(XirSite site, XirArgument[] arguments, RiMethod method) { + return null; + } + + @Override + public XirSnippet genInvokeInterface(XirSite site, XirArgument receiver, RiMethod method) { + return new XirSnippet(invokeInterfaceTemplates.get(site), receiver, XirArgument.forWord(0)); + } + + @Override + public XirSnippet genInvokeVirtual(XirSite site, XirArgument receiver, RiMethod method) { + return new XirSnippet(invokeVirtualTemplates.get(site), receiver, XirArgument.forWord(0)); + } + + @Override + public XirSnippet genInvokeSpecial(XirSite site, XirArgument receiver, RiMethod method) { + return new XirSnippet(invokeSpecialTemplates.get(site), receiver, XirArgument.forWord(0)); + } + + @Override + public XirSnippet genInvokeStatic(XirSite site, RiMethod method) { + return new XirSnippet(invokeStaticTemplates.get(site), XirArgument.forWord(0)); + } + + @Override + public XirSnippet genMonitorEnter(XirSite site, XirArgument receiver, XirArgument lockAddress) { + return new XirSnippet(monitorEnterTemplates.get(site), receiver, lockAddress); + } + + @Override + public XirSnippet genMonitorExit(XirSite site, XirArgument receiver, XirArgument lockAddress) { + return new XirSnippet(monitorExitTemplates.get(site), receiver, lockAddress); + } + + @Override + public XirSnippet genGetField(XirSite site, XirArgument object, RiField field) { + assert field.isResolved(); + return new XirSnippet(getFieldTemplates.get(site, field.kind()), object, XirArgument.forInt(((HotSpotField) field).offset())); + } + + @Override + public XirSnippet genWriteBarrier(XirArgument object) { + return new XirSnippet(writeBarrierTemplate.get(null, CiKind.Void), object); + } + + @Override + public XirSnippet genPutField(XirSite site, XirArgument object, RiField field, XirArgument value) { + assert field.isResolved(); + return new XirSnippet(putFieldTemplates.get(site, field.kind()), object, value, XirArgument.forInt(((HotSpotField) field).offset())); + } + + @Override + public XirSnippet genGetStatic(XirSite site, XirArgument object, RiField field) { + assert field.isResolved(); + return new XirSnippet(getFieldTemplates.get(site, field.kind()), object, XirArgument.forInt(((HotSpotField) field).offset())); + } + + @Override + public XirSnippet genPutStatic(XirSite site, XirArgument object, RiField field, XirArgument value) { + assert field.isResolved(); + return new XirSnippet(putFieldTemplates.get(site, field.kind()), object, value, XirArgument.forInt(((HotSpotField) field).offset())); + } + + @Override + public XirSnippet genNewInstance(XirSite site, RiType type) { + assert type.isResolved(); + int instanceSize = ((HotSpotTypeResolved) type).instanceSize(); + return new XirSnippet(newInstanceTemplates.get(site, instanceSize), XirArgument.forObject(type)); + } + + @Override + public XirSnippet genNewArray(XirSite site, XirArgument length, CiKind elementKind, RiType componentType, RiType arrayType) { + if (elementKind == CiKind.Object) { + assert arrayType.isResolved(); + return new XirSnippet(newObjectArrayTemplates.get(site), length, XirArgument.forObject(arrayType)); + } + assert arrayType == null; + arrayType = compiler.getVMEntries().getPrimitiveArrayType(elementKind); + return new XirSnippet(newTypeArrayTemplates.get(site, elementKind), length, XirArgument.forObject(arrayType)); + } + + @Override + public XirSnippet genNewObjectArrayClone(XirSite site, XirArgument newLength, XirArgument referenceArray) { + return new XirSnippet(newObjectArrayCloneTemplates.get(site), newLength, referenceArray); + } + + @Override + public XirSnippet genNewMultiArray(XirSite site, XirArgument[] lengths, RiType type) { + assert type.isResolved(); + XirArgument[] params = Arrays.copyOf(lengths, lengths.length + 1); + params[lengths.length] = XirArgument.forObject(type); + return new XirSnippet(multiNewArrayTemplate.get(site, lengths.length), params); + } + + @Override + public XirSnippet genCheckCast(XirSite site, XirArgument receiver, XirArgument hub, RiType type) { + assert type.isResolved(); + return new XirSnippet(checkCastTemplates.get(site), receiver, hub); + } + + @Override + public XirSnippet genInstanceOf(XirSite site, XirArgument object, XirArgument hub, RiType type) { + assert type.isResolved(); + return new XirSnippet(instanceOfTemplates.get(site), object, hub); + } + + @Override + public XirSnippet genArrayLoad(XirSite site, XirArgument array, XirArgument index, XirArgument length, CiKind elementKind, RiType elementType) { + if (length == null || !site.requiresBoundsCheck()) { + return new XirSnippet(arrayLoadTemplates.get(site, elementKind), array, index); + } + return new XirSnippet(arrayLoadTemplates.get(site, elementKind, GIVEN_LENGTH), array, index, length); + } + + @Override + public XirSnippet genArrayStore(XirSite site, XirArgument array, XirArgument index, XirArgument length, XirArgument value, CiKind elementKind, RiType elementType) { + if (length == null || !site.requiresBoundsCheck()) { + return new XirSnippet(arrayStoreTemplates.get(site, elementKind), array, index, value); + } + return new XirSnippet(arrayStoreTemplates.get(site, elementKind, GIVEN_LENGTH), array, index, value, length); + } + + @Override + public XirSnippet genArrayCopy(XirSite site, XirArgument src, XirArgument srcPos, XirArgument dest, XirArgument destPos, XirArgument length, RiType elementType, boolean inputsSame, boolean inputsDifferent) { + if (elementType == null) { + return null; + } + assert !inputsDifferent || !inputsSame; + XirTemplate template = null; + if (inputsDifferent) { + template = arrayCopyTemplates.get(site, elementType.kind(), INPUTS_DIFFERENT); + } else if (inputsSame) { + template = arrayCopyTemplates.get(site, elementType.kind(), INPUTS_SAME); + } else { + template = arrayCopyTemplates.get(site, elementType.kind()); + } + return new XirSnippet(template, src, srcPos, dest, destPos, length); + } + + @Override + public XirSnippet genArrayLength(XirSite site, XirArgument array) { + return new XirSnippet(arrayLengthTemplates.get(site), array); + } + + @Override + public List buildTemplates(CiXirAssembler asm) { + this.globalAsm = asm; + List templates = new ArrayList(); + return templates; + } + + private void verifyPointer(CiXirAssembler asm, XirOperand pointer) { + if (config.verifyPointers) { + // The verify pointer stub wants the argument in a fixed register. + XirOperand fixed = asm.createRegisterTemp("fixed", CiKind.Object, AMD64.r13); + asm.push(fixed); + asm.mov(fixed, pointer); + asm.callRuntime(config.verifyPointerStub, null); + asm.pop(fixed); + } + } + + private void checkSubtype(CiXirAssembler asm, XirOperand result, XirOperand objHub, XirOperand hub) { + asm.push(objHub); + asm.push(hub); + asm.callRuntime(config.instanceofStub, null); + asm.pop(result); + asm.pop(result); + } + + private void useRegisters(CiXirAssembler asm, CiRegister... registers) { + if (registers != null) { + for (CiRegister register : registers) { + asm.createRegisterTemp("reg", CiKind.Illegal, register); + } + } + } + + private void writeBarrier(CiXirAssembler asm, XirOperand base) { + asm.shr(base, base, asm.i(config.cardtableShift)); + asm.pstore(CiKind.Boolean, asm.w(config.cardtableStartAddress), base, asm.b(false), false); + } + + public boolean is(TemplateFlag check, long flags) { + return (flags & check.bits()) == check.bits(); + } + + /** + * Base class for all the ondemand template generators. It is not normally subclassed directly, but through one of + * its subclasses (SimpleTemplates, KindTemplates, IndexTemplates). + * + * @author Lukas Stadler + */ + private abstract class Templates { + + private ConcurrentHashMap templates = new ConcurrentHashMap(); + private final long mask; + + /** + * Each flag passed to this method will cause templates with and without it to be generated. + */ + public Templates(TemplateFlag... flags) { + this.mask = getBits((int) INDEX_MASK, null, flags); + } + + protected abstract XirTemplate create(CiXirAssembler asm, long flags); + + protected long getBits(int index, XirSite site, TemplateFlag... flags) { + long bits = index; + if (site != null) { + bits |= site.requiresNullCheck() ? NULL_CHECK.bits() : 0; + bits |= site.requiresReadBarrier() ? READ_BARRIER.bits() : 0; + bits |= site.requiresWriteBarrier() ? WRITE_BARRIER.bits() : 0; + bits |= site.requiresArrayStoreCheck() ? STORE_CHECK.bits() : 0; + bits |= site.requiresBoundsCheck() ? BOUNDS_CHECK.bits() : 0; + } + if (flags != null) { + for (TemplateFlag flag : flags) { + bits |= flag.bits(); + } + } + return bits; + } + + protected XirTemplate getInternal(long flags) { + flags = flags & mask; + XirTemplate template = templates.get(flags); + if (template == null) { + template = create(HotSpotXirGenerator.this.globalAsm.copy(), flags); + templates.put(flags, template); + } + return template; + } + } + + private abstract class SimpleTemplates extends Templates { + + public SimpleTemplates(TemplateFlag... flags) { + super(flags); + } + + public XirTemplate get(XirSite site, TemplateFlag... flags) { + return getInternal(getBits(0, site, flags)); + } + } + + private abstract class IndexTemplates extends Templates { + + public IndexTemplates(TemplateFlag... flags) { + super(flags); + } + + @Override + protected final XirTemplate create(CiXirAssembler asm, long flags) { + return create(asm, flags & FLAGS_MASK, (int) (flags & INDEX_MASK)); + } + + protected abstract XirTemplate create(CiXirAssembler asm, long flags, int index); + + public XirTemplate get(XirSite site, int size, TemplateFlag... flags) { + return getInternal(getBits(size, site, flags)); + } + } + + private abstract class KindTemplates extends Templates { + + public KindTemplates(TemplateFlag... flags) { + super(flags); + } + + @Override + protected final XirTemplate create(CiXirAssembler asm, long flags) { + return create(asm, flags & FLAGS_MASK, CiKind.VALUES[(int) (flags & INDEX_MASK)]); + } + + protected abstract XirTemplate create(CiXirAssembler asm, long flags, CiKind kind); + + public XirTemplate get(XirSite site, CiKind kind, TemplateFlag... flags) { + return getInternal(getBits(kind.ordinal(), site, flags)); + } + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/InvocationSocket.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/InvocationSocket.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,276 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.runtime; + +import java.io.*; +import java.lang.reflect.*; +import java.util.*; + +import com.oracle.max.graal.runtime.logging.*; + +/** + * A collection of java.lang.reflect proxies that communicate over a socket connection. + * + * Calling a method sends the method name and the parameters through the socket. Afterwards this class waits for a + * result. While waiting for a result three types of objects can arrive through the socket: a method invocation, a + * method result or an exception. Method invocation can thus be recursive. + */ +public class InvocationSocket { + + private static final boolean DEBUG = false; + private static final boolean COUNT_CALLS = false; + + private static final HashSet cachedMethodNames = new HashSet(); + private static final HashSet forbiddenMethodNames = new HashSet(); + + static { + cachedMethodNames.add("name"); + cachedMethodNames.add("kind"); + cachedMethodNames.add("isResolved"); + cachedMethodNames.add("getVMEntries"); + cachedMethodNames.add("exactType"); + cachedMethodNames.add("isInitialized"); + forbiddenMethodNames.add("javaClass"); + } + + private final ObjectOutputStream output; + private final ObjectInputStream input; + + private final Map counts = new HashMap(); + + public InvocationSocket(ObjectOutputStream output, ObjectInputStream input) { + this.output = output; + this.input = input; + + if (COUNT_CALLS) { + Runtime.getRuntime().addShutdownHook(new Thread() { + @Override + public void run() { + SortedMap sorted = new TreeMap(); + for (Map.Entry entry : counts.entrySet()) { + sorted.put(entry.getValue(), entry.getKey()); + } + for (Map.Entry entry : sorted.entrySet()) { + System.out.println(entry.getKey() + ": " + entry.getValue()); + } + } + }); + } + } + + /** + * Represents one invocation of a method that is transferred via the socket connection. + * + * @author Lukas Stadler + */ + private static class Invocation implements Serializable { + + public Object receiver; + public String methodName; + public Object[] args; + + public Invocation(Object receiver, String methodName, Object[] args) { + this.receiver = receiver; + this.methodName = methodName; + this.args = args; + } + } + + /** + * Represents the result of an invocation that is transferred via the socket connection. + * + * @author Lukas Stadler + */ + private static class Result implements Serializable { + + public Object result; + + public Result(Object result) { + this.result = result; + } + } + + private void incCount(String name, Object[] args) { + if (COUNT_CALLS) { + name = name + (args == null ? 0 : args.length); + if (counts.get(name) != null) { + counts.put(name, counts.get(name) + 1); + } else { + counts.put(name, 1); + } + } + } + + /** + * Each instance of this class handles remote invocations for one instance of a Remote class. It will forward all + * interface methods to the other end of the socket and cache the results of calls to certain methods. + * + * @author Lukas Stadler + */ + public class Handler implements InvocationHandler { + + private final Object receiver; + private final HashMap cache = new HashMap(); + + public Handler(Object receiver) { + this.receiver = receiver; + } + + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + // only interface methods can be transferred, java.lang.Object methods + if (method.getDeclaringClass() == Object.class) { + return method.invoke(receiver, args); + } + String methodName = method.getName(); + // check if the result of this zero-arg method was cached + if (args == null || args.length == 0) { + if (cache.containsKey(methodName)) { + return cache.get(methodName); + } + } + if (forbiddenMethodNames.contains(methodName)) { + throw new IllegalAccessException(methodName + " not allowed"); + } + Object result = null; + try { + if (DEBUG) { + Logger.startScope("invoking remote " + methodName); + } + incCount(methodName, args); + + output.writeObject(new Invocation(receiver, methodName, args)); + output.flush(); + result = waitForResult(false); + + // result caching for selected methods + if ((args == null || args.length == 0) && cachedMethodNames.contains(methodName)) { + cache.put(methodName, result); + } + return result; + } catch (Throwable t) { + t.printStackTrace(); + throw t; + } finally { + if (DEBUG) { + Logger.endScope(" = " + result); + } + } + } + } + + /** + * Waits for the result of a remote method invocation. Invocations that should be executed in this VM might arrive + * while waiting for the result, and these invocations will be executed before again waiting fort he result. + */ + public Object waitForResult(boolean eofExpected) throws IOException, ClassNotFoundException { + while (true) { + Object in; + try { + in = input.readObject(); + } catch (EOFException e) { + if (eofExpected) { + return null; + } + throw e; + } + if (in instanceof Result) { + return ((Result) in).result; + } else if (in instanceof RuntimeException) { + throw (RuntimeException) in; + } else if (in instanceof Throwable) { + throw new RuntimeException((Throwable) in); + } + + Invocation invoke = (Invocation) in; + Method method = null; + for (Class clazz = invoke.receiver.getClass(); clazz != null; clazz = clazz.getSuperclass()) { + for (Method m : clazz.getDeclaredMethods()) { + if (invoke.methodName.equals(m.getName())) { + method = m; + break; + } + } + } + if (method == null) { + Exception e = new UnsupportedOperationException("unknown method " + invoke.methodName); + e.printStackTrace(); + output.writeObject(e); + output.flush(); + } else { + Object result = null; + try { + if (invoke.args == null) { + if (DEBUG) { + Logger.startScope("invoking local " + invoke.methodName); + } + result = method.invoke(invoke.receiver); + } else { + if (Logger.ENABLED && DEBUG) { + StringBuilder str = new StringBuilder(); + str.append("invoking local " + invoke.methodName + "("); + for (int i = 0; i < invoke.args.length; i++) { + str.append(i == 0 ? "" : ", "); + str.append(Logger.pretty(invoke.args[i])); + } + str.append(")"); + Logger.startScope(str.toString()); + } + result = method.invoke(invoke.receiver, invoke.args); + } + result = new Result(result); + } catch (IllegalArgumentException e) { + System.out.println("error while invoking " + invoke.methodName); + e.getCause().printStackTrace(); + result = e.getCause(); + } catch (InvocationTargetException e) { + System.out.println("error while invoking " + invoke.methodName); + e.getCause().printStackTrace(); + result = e.getCause(); + } catch (IllegalAccessException e) { + System.out.println("error while invoking " + invoke.methodName); + e.getCause().printStackTrace(); + result = e.getCause(); + } finally { + if (DEBUG) { + if (result instanceof Result) { + Logger.endScope(" = " + ((Result) result).result); + } else { + Logger.endScope(" = " + result); + } + } + } + output.writeObject(result); + output.flush(); + } + } + } + + /** + * Sends a result without invoking a method, used by CompilationServer startup code. + */ + public void sendResult(Object obj) throws IOException { + output.writeObject(new Result(obj)); + output.flush(); + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/TemplateFlag.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/TemplateFlag.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.runtime; + +enum TemplateFlag { + NULL_CHECK, READ_BARRIER, WRITE_BARRIER, STORE_CHECK, BOUNDS_CHECK, GIVEN_LENGTH, INPUTS_DIFFERENT, INPUTS_SAME, STATIC_METHOD, SYNCHRONIZED; + + private static final long FIRST_FLAG = 0x0000000100000000L; + public static final long FLAGS_MASK = 0x0000FFFF00000000L; + public static final long INDEX_MASK = 0x00000000FFFFFFFFL; + + public long bits() { + assert ((FIRST_FLAG << ordinal()) & FLAGS_MASK) != 0; + return FIRST_FLAG << ordinal(); + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/VMEntries.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/VMEntries.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.max.graal.runtime; + +import com.sun.cri.ci.*; +import com.sun.cri.ri.*; + +/** + * Entries into the HotSpot VM from Java code. + */ +public interface VMEntries { + + // Checkstyle: stop + + byte[] RiMethod_code(long vmId); + + int RiMethod_maxStackSize(long vmId); + + int RiMethod_maxLocals(long vmId); + + RiType RiMethod_holder(long vmId); + + String RiMethod_signature(long vmId); + + int RiMethod_accessFlags(long vmId); + + RiType RiSignature_lookupType(String returnType, HotSpotTypeResolved accessingClass); + + Object RiConstantPool_lookupConstant(long vmId, int cpi); + + RiMethod RiConstantPool_lookupMethod(long vmId, int cpi, byte byteCode); + + RiSignature RiConstantPool_lookupSignature(long vmId, int cpi); + + RiType RiConstantPool_lookupType(long vmId, int cpi); + + RiField RiConstantPool_lookupField(long vmId, int cpi, byte byteCode); + + RiConstantPool RiType_constantPool(HotSpotTypeResolved klass); + + void installMethod(HotSpotTargetMethod targetMethod); + + long installStub(HotSpotTargetMethod targetMethod); + + HotSpotVMConfig getConfiguration(); + + RiExceptionHandler[] RiMethod_exceptionHandlers(long vmId); + + RiMethod RiType_resolveMethodImpl(HotSpotTypeResolved klass, String name, String signature); + + boolean RiType_isSubtypeOf(HotSpotTypeResolved klass, RiType other); + + RiType getPrimitiveArrayType(CiKind kind); + + RiType RiType_arrayOf(HotSpotTypeResolved klass); + + RiType RiType_componentType(HotSpotTypeResolved klass); + + RiType getType(Class javaClass); + + boolean RiMethod_hasBalancedMonitors(long vmId); + + RiMethod RiMethod_uniqueConcreteMethod(long vmId); + + void recordBailout(String reason); + + RiType RiType_uniqueConcreteSubtype(HotSpotTypeResolved hotSpotTypeResolved); + + RiType RiType_superType(HotSpotTypeResolved hotSpotTypeResolved); + + int getArrayLength(CiConstant array); + + boolean compareConstantObjects(CiConstant x, CiConstant y); + + RiType getRiType(CiConstant constant); + + // Checkstyle: resume +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/VMEntriesNative.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/VMEntriesNative.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.max.graal.runtime; + +import java.lang.reflect.*; + +import com.oracle.max.graal.runtime.server.*; +import com.sun.cri.ci.*; +import com.sun.cri.ri.*; + +/** + * Entries into the HotSpot VM from Java code. + */ +public class VMEntriesNative implements VMEntries, Remote { + + // Checkstyle: stop + @Override + public native byte[] RiMethod_code(long vmId); + + @Override + public native int RiMethod_maxStackSize(long vmId); + + @Override + public native int RiMethod_maxLocals(long vmId); + + @Override + public native RiType RiMethod_holder(long vmId); + + @Override + public native String RiMethod_signature(long vmId); + + @Override + public native int RiMethod_accessFlags(long vmId); + + @Override + public native RiType RiSignature_lookupType(String returnType, HotSpotTypeResolved accessingClass); + + @Override + public native Object RiConstantPool_lookupConstant(long vmId, int cpi); + + @Override + public native RiMethod RiConstantPool_lookupMethod(long vmId, int cpi, byte byteCode); + + @Override + public native RiSignature RiConstantPool_lookupSignature(long vmId, int cpi); + + @Override + public native RiType RiConstantPool_lookupType(long vmId, int cpi); + + @Override + public native RiField RiConstantPool_lookupField(long vmId, int cpi, byte byteCode); + + @Override + public native RiConstantPool RiType_constantPool(HotSpotTypeResolved klass); + + @Override + public native void installMethod(HotSpotTargetMethod targetMethod); + + @Override + public native long installStub(HotSpotTargetMethod targetMethod); + + @Override + public native HotSpotVMConfig getConfiguration(); + + @Override + public native RiExceptionHandler[] RiMethod_exceptionHandlers(long vmId); + + @Override + public native RiMethod RiType_resolveMethodImpl(HotSpotTypeResolved klass, String name, String signature); + + @Override + public native boolean RiType_isSubtypeOf(HotSpotTypeResolved klass, RiType other); + + @Override + public native RiType getPrimitiveArrayType(CiKind kind); + + @Override + public native RiType RiType_arrayOf(HotSpotTypeResolved klass); + + @Override + public native RiType RiType_componentType(HotSpotTypeResolved klass); + + @Override + public native RiType RiType_uniqueConcreteSubtype(HotSpotTypeResolved klass); + + @Override + public native RiType RiType_superType(HotSpotTypeResolved klass); + + @Override + public native RiType getType(Class javaClass); + + @Override + public native boolean RiMethod_hasBalancedMonitors(long vmId); + + @Override + public native void recordBailout(String reason); + + @Override + public native RiMethod RiMethod_uniqueConcreteMethod(long vmId); + + @Override + public int getArrayLength(CiConstant array) { + return Array.getLength(array.asObject()); + } + + @Override + public boolean compareConstantObjects(CiConstant x, CiConstant y) { + return x.asObject() == y.asObject(); + } + + @Override + public RiType getRiType(CiConstant constant) { + Object o = constant.asObject(); + if (o == null) { + return null; + } + return getType(o.getClass()); + } + + // Checkstyle: resume +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/VMExits.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/VMExits.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.max.graal.runtime; + +import com.sun.cri.ci.*; +import com.sun.cri.ri.*; + +/** + * Exits from the HotSpot VM into Java code. + */ +public interface VMExits { + + void compileMethod(long methodVmId, String name, int entryBCI) throws Throwable; + + RiMethod createRiMethodResolved(long vmId, String name); + + RiMethod createRiMethodUnresolved(String name, String signature, RiType holder); + + RiSignature createRiSignature(String signature); + + RiField createRiField(RiType holder, String name, RiType type, int offset, int flags); + + RiType createRiType(long vmId, String name); + + RiType createRiTypePrimitive(int basicType); + + RiType createRiTypeUnresolved(String name); + + RiConstantPool createRiConstantPool(long vmId); + + CiConstant createCiConstant(CiKind kind, long value); + + CiConstant createCiConstantFloat(float value); + + CiConstant createCiConstantDouble(double value); + + CiConstant createCiConstantObject(Object object); + +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/VMExitsNative.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/VMExitsNative.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,218 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.max.graal.runtime; + +import java.io.*; +import java.util.*; + +import com.oracle.max.graal.compiler.*; +import com.oracle.max.graal.compiler.debug.*; +import com.oracle.max.graal.runtime.logging.*; +import com.oracle.max.graal.runtime.server.*; +import com.sun.cri.ci.*; +import com.sun.cri.ri.*; + +/** + * Exits from the HotSpot VM into Java code. + */ +public class VMExitsNative implements VMExits, Remote { + + public static final boolean LogCompiledMethods = false; + public static boolean compileMethods = true; + + private final Compiler compiler; + + public final HotSpotTypePrimitive typeBoolean; + public final HotSpotTypePrimitive typeChar; + public final HotSpotTypePrimitive typeFloat; + public final HotSpotTypePrimitive typeDouble; + public final HotSpotTypePrimitive typeByte; + public final HotSpotTypePrimitive typeShort; + public final HotSpotTypePrimitive typeInt; + public final HotSpotTypePrimitive typeLong; + public final HotSpotTypePrimitive typeVoid; + + public VMExitsNative(Compiler compiler) { + this.compiler = compiler; + + typeBoolean = new HotSpotTypePrimitive(compiler, CiKind.Boolean); + typeChar = new HotSpotTypePrimitive(compiler, CiKind.Char); + typeFloat = new HotSpotTypePrimitive(compiler, CiKind.Float); + typeDouble = new HotSpotTypePrimitive(compiler, CiKind.Double); + typeByte = new HotSpotTypePrimitive(compiler, CiKind.Byte); + typeShort = new HotSpotTypePrimitive(compiler, CiKind.Short); + typeInt = new HotSpotTypePrimitive(compiler, CiKind.Int); + typeLong = new HotSpotTypePrimitive(compiler, CiKind.Long); + typeVoid = new HotSpotTypePrimitive(compiler, CiKind.Void); + } + + private static Set compiledMethods = new HashSet(); + + @Override + public void compileMethod(long methodVmId, String name, int entryBCI) throws Throwable { + if (!compileMethods) { + return; + } + + try { + HotSpotMethodResolved riMethod = new HotSpotMethodResolved(compiler, methodVmId, name); + CiResult result = compiler.getCompiler().compileMethod(riMethod, -1, null, null); + if (LogCompiledMethods) { + String qualifiedName = CiUtil.toJavaName(riMethod.holder()) + "::" + riMethod.name(); + compiledMethods.add(qualifiedName); + } + + if (result.bailout() != null) { + Throwable cause = result.bailout().getCause(); + if (!C1XOptions.QuietBailout) { + StringWriter out = new StringWriter(); + result.bailout().printStackTrace(new PrintWriter(out)); + TTY.println("Bailout:\n" + out.toString()); + if (cause != null) { + Logger.info("Trace for cause: "); + for (StackTraceElement e : cause.getStackTrace()) { + String current = e.getClassName() + "::" + e.getMethodName(); + String type = ""; + if (compiledMethods.contains(current)) { + type = "compiled"; + } + Logger.info(String.format("%-10s %3d %s", type, e.getLineNumber(), current)); + } + } + } + String s = result.bailout().getMessage(); + if (cause != null) { + s = cause.getMessage(); + } + compiler.getVMEntries().recordBailout(s); + } else { + HotSpotTargetMethod.installMethod(compiler, riMethod, result.targetMethod()); + } + } catch (Throwable t) { + StringWriter out = new StringWriter(); + t.printStackTrace(new PrintWriter(out)); + TTY.println("Compilation interrupted: (" + name + ")\n" + out.toString()); + throw t; + } + } + + @Override + public RiMethod createRiMethodResolved(long vmId, String name) { + return new HotSpotMethodResolved(compiler, vmId, name); + } + + @Override + public RiMethod createRiMethodUnresolved(String name, String signature, RiType holder) { + return new HotSpotMethodUnresolved(compiler, name, signature, holder); + } + + @Override + public RiSignature createRiSignature(String signature) { + return new HotSpotSignature(compiler, signature); + } + + @Override + public RiField createRiField(RiType holder, String name, RiType type, int offset, int flags) { + if (offset != -1) { + HotSpotTypeResolved resolved = (HotSpotTypeResolved) holder; + return resolved.createRiField(name, type, offset, flags); + } + return new HotSpotField(compiler, holder, name, type, offset, flags); + } + + @Override + public RiType createRiType(long vmId, String name) { + throw new RuntimeException("not implemented"); + } + + @Override + public RiType createRiTypePrimitive(int basicType) { + switch (basicType) { + case 4: + return typeBoolean; + case 5: + return typeChar; + case 6: + return typeFloat; + case 7: + return typeDouble; + case 8: + return typeByte; + case 9: + return typeShort; + case 10: + return typeInt; + case 11: + return typeLong; + case 14: + return typeVoid; + default: + throw new IllegalArgumentException("Unknown basic type: " + basicType); + } + } + + @Override + public RiType createRiTypeUnresolved(String name) { + return new HotSpotTypeUnresolved(compiler, name); + } + + @Override + public RiConstantPool createRiConstantPool(long vmId) { + return new HotSpotConstantPool(compiler, vmId); + } + + @Override + public CiConstant createCiConstant(CiKind kind, long value) { + if (kind == CiKind.Long) { + return CiConstant.forLong(value); + } else if (kind == CiKind.Int) { + return CiConstant.forInt((int) value); + } else if (kind == CiKind.Short) { + return CiConstant.forShort((short) value); + } else if (kind == CiKind.Char) { + return CiConstant.forChar((char) value); + } else if (kind == CiKind.Byte) { + return CiConstant.forByte((byte) value); + } else if (kind == CiKind.Boolean) { + return (value == 0) ? CiConstant.FALSE : CiConstant.TRUE; + } else { + throw new IllegalArgumentException(); + } + } + + @Override + public CiConstant createCiConstantFloat(float value) { + return CiConstant.forFloat(value); + } + + @Override + public CiConstant createCiConstantDouble(double value) { + return CiConstant.forDouble(value); + } + + @Override + public CiConstant createCiConstantObject(Object object) { + return CiConstant.forObject(object); + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/logging/CountingProxy.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/logging/CountingProxy.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.runtime.logging; + +import java.lang.reflect.*; +import java.util.*; + +import com.oracle.max.graal.runtime.server.*; + +/** + * A java.lang.reflect proxy that hierarchically logs all method invocations along with their parameters and return + * values. + */ +public class CountingProxy implements InvocationHandler { + + public static final boolean ENABLED = Boolean.valueOf(System.getProperty("c1x.countcalls")); + + private T delegate; + + private Map calls = new HashMap(); + + public CountingProxy(T delegate) { + assert ENABLED; + System.out.println("Counting proxy for " + delegate.getClass().getSimpleName() + " created"); + this.delegate = delegate; + proxies.add(this); + } + + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + int argCount = args == null ? 0 : args.length; + if (method.getParameterTypes().length != argCount) { + throw new RuntimeException("wrong parameter count"); + } + final Object result; + long count = calls.containsKey(method) ? calls.get(method) : 0; + calls.put(method, count + 1); + try { + if (args == null) { + result = method.invoke(delegate); + } else { + result = method.invoke(delegate, args); + } + } catch (InvocationTargetException e) { + throw e.getCause(); + } + return result; + } + + public static T getProxy(Class interf, T delegate) { + Class[] interfaces = ReplacingStreams.getAllInterfaces(delegate.getClass()); + Object obj = Proxy.newProxyInstance(interf.getClassLoader(), interfaces, new CountingProxy(delegate)); + return interf.cast(obj); + } + + private static ArrayList proxies = new ArrayList(); + + static { + if (ENABLED) { + Runtime.getRuntime().addShutdownHook(new Thread() { + + @Override + public void run() { + for (CountingProxy proxy : proxies) { + proxy.print(); + } + } + }); + } + } + + protected void print() { + long sum = 0; + for (Map.Entry entry : calls.entrySet()) { + Method method = entry.getKey(); + long count = entry.getValue(); + sum += count; + System.out.println(delegate.getClass().getSimpleName() + "." + method.getName() + ": " + count); + } + System.out.println(delegate.getClass().getSimpleName() + " calls: " + sum); + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/logging/Logger.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/logging/Logger.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.runtime.logging; + +import java.io.*; +import java.lang.reflect.*; +import java.util.*; + +/** + * Scoped logging class used to display the call hierarchy of VMEntries/VMExits calls. + */ +public class Logger { + + public static final boolean ENABLED = Boolean.valueOf(System.getProperty("c1x.debug")); + private static final int SPACING = 4; + private static Deque openStack = new LinkedList(); + private static boolean open = false; + private static int level = 0; + + private static final PrintStream out; + + static { + PrintStream ps = null; + String filename = System.getProperty("c1x.info_file"); + if (filename != null && !"".equals(filename)) { + try { + ps = new PrintStream(new FileOutputStream(filename)); + } catch (FileNotFoundException e) { + e.printStackTrace(); + ps = null; + } + } + out = ps; + if (out != null) { + out.println("start: " + new Date()); + } + } + + public static void info(String message) { + if (ENABLED) { + log(message); + } else { + System.out.println(message); + } + if (out != null) { + out.println(message); + out.flush(); + } + } + + public static void log(String message) { + if (ENABLED) { + for (String line : message.split("\n")) { + if (open) { + System.out.println("..."); + open = false; + } + System.out.print(space(level)); + System.out.println(line); + } + } + } + + public static void startScope(String message) { + if (ENABLED) { + if (open) { + System.out.println("..."); + open = false; + } + System.out.print(space(level)); + System.out.print(message); + openStack.push(open); + open = true; + level++; + } + } + + public static void endScope(String message) { + if (ENABLED) { + level--; + if (open) { + System.out.println(message); + } else { + System.out.println(space(level) + "..." + message); + } + open = openStack.pop(); + } + } + + private static String[] spaces = new String[50]; + + private static String space(int count) { + assert count >= 0; + String result; + if (count >= spaces.length || spaces[count] == null) { + StringBuilder str = new StringBuilder(); + for (int i = 0; i < count * SPACING; i++) { + str.append(' '); + } + result = str.toString(); + if (count < spaces.length) { + spaces[count] = result; + } + } else { + result = spaces[count]; + } + return result; + } + + public static String pretty(Object value) { + if (value == null) { + return "null"; + } + + Class klass = value.getClass(); + if (value instanceof Void) { + return "void"; + } else if (value instanceof String) { + return "\"" + value + "\""; + } else if (value instanceof Method) { + return "method \"" + ((Method) value).getName() + "\""; + } else if (value instanceof Class) { + return "class \"" + ((Class) value).getSimpleName() + "\""; + } else if (value instanceof Integer) { + if ((Integer) value < 10) { + return value.toString(); + } + return value + " (0x" + Integer.toHexString((Integer) value) + ")"; + } else if (value instanceof Long) { + if ((Long) value < 10) { + return value + "l"; + } + return value + "l (0x" + Long.toHexString((Long) value) + "l)"; + } else if (klass.isArray()) { + StringBuilder str = new StringBuilder(); + int dimensions = 0; + while (klass.isArray()) { + dimensions++; + klass = klass.getComponentType(); + } + str.append(klass.getSimpleName()).append('[').append(Array.getLength(value)).append(']'); + for (int i = 1; i < dimensions; i++) { + str.append("[]"); + } + return str.toString(); + } + + return value.toString(); + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/logging/LoggingProxy.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/logging/LoggingProxy.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.runtime.logging; + +import java.lang.reflect.*; + +import com.oracle.max.graal.runtime.server.*; + +/** + * A java.lang.reflect proxy that hierarchically logs all method invocations along with their parameters and return values. + */ +public class LoggingProxy implements InvocationHandler { + + private T delegate; + + public LoggingProxy(T delegate) { + this.delegate = delegate; + } + + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + int argCount = args == null ? 0 : args.length; + if (method.getParameterTypes().length != argCount) { + throw new RuntimeException("wrong parameter count"); + } + StringBuilder str = new StringBuilder(); + str.append(method.getReturnType().getSimpleName() + " " + method.getDeclaringClass().getSimpleName() + "." + method.getName() + "("); + for (int i = 0; i < argCount; i++) { + str.append(i == 0 ? "" : ", "); + str.append(Logger.pretty(args[i])); + } + str.append(")"); + Logger.startScope(str.toString()); + final Object result; + try { + if (args == null) { + result = method.invoke(delegate); + } else { + result = method.invoke(delegate, args); + } + } catch (InvocationTargetException e) { + Logger.endScope(" = Exception " + e.getMessage()); + throw e.getCause(); + } + Logger.endScope(" = " + Logger.pretty(result)); + return result; + } + + /** + * The object returned by this method will implement all interfaces that are implemented by delegate. + */ + public static T getProxy(Class interf, T delegate) { + Class[] interfaces = ReplacingStreams.getAllInterfaces(delegate.getClass()); + Object obj = Proxy.newProxyInstance(interf.getClassLoader(), interfaces, new LoggingProxy(delegate)); + return interf.cast(obj); + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/logging/package-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/logging/package-info.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +/** + * Logging framework for the HotSpot CRI implementation. + * + * @author Lukas Stadler + * @author Thomas Wuerthinger + */ +package com.oracle.max.graal.runtime.logging; diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/package-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/package-info.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +/** + * Package containing the runtime interface (defined in the CRI project) implementation for HotSpot. + * There is a class that bridges from the C++ to the Java side (VMExitsNative.java) and one that bridges + * from the Java to the C++ side (VMEntriesNative.java). + * + * @author Lukas Stadler + * @author Thomas Wuerthinger + */ +package com.oracle.max.graal.runtime; diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/server/CompilationServer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/server/CompilationServer.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.runtime.server; + +import java.io.*; +import java.net.*; +import java.util.*; + +import javax.net.*; + +import com.oracle.max.graal.runtime.*; +import com.oracle.max.graal.runtime.Compiler; +import com.oracle.max.graal.runtime.logging.*; + +/** + * Server side of the client/server compilation model. The server listens for connections on the hardcoded port 1199. + * + * @author Lukas Stadler + */ +public class CompilationServer implements Runnable { + + public static void main(String[] args) throws Exception { + new CompilationServer(false).run(); + } + + public static interface ConnectionObserver { + + void connectionStarted(Compiler compiler); + + void connectionFinished(Compiler compiler); + } + + private final boolean multiple; + private final ArrayList observers = new ArrayList(); + + /** + * Creates a new Compilation server. The server is activated by calling {@link #run()} directly or via a new + * {@link Thread}. + * + * @param multiple true if the server should server should serve an infinite amount of consecutive connections, + * false if it should terminate after the first connection ends. + */ + public CompilationServer(boolean multiple) { + this.multiple = multiple; + HotSpotOptions.setDefaultOptions(); + } + + public void addConnectionObserver(ConnectionObserver observer) { + observers.add(observer); + } + + public void removeConnectionObserver(ConnectionObserver observer) { + observers.remove(observer); + } + + public void run() { + final ServerSocket serverSocket; + try { + serverSocket = ServerSocketFactory.getDefault().createServerSocket(1199); + } catch (IOException e) { + throw new RuntimeException("Couldn't create compilation server", e); + } + do { + Socket socket = null; + try { + Logger.log("Compilation server ready, waiting for client to connect..."); + socket = serverSocket.accept(); + Logger.log("Connected to " + socket.getRemoteSocketAddress()); + + ReplacingStreams streams = new ReplacingStreams(socket.getOutputStream(), socket.getInputStream()); + + // get the VMEntries proxy from the client + VMEntries entries = (VMEntries) streams.getInvocation().waitForResult(false); + + // return the initialized compiler to the client + Compiler compiler = CompilerImpl.initializeServer(entries); + compiler.getCompiler(); + streams.getInvocation().sendResult(compiler); + + for (ConnectionObserver observer : observers) { + observer.connectionStarted(compiler); + } + + streams.getInvocation().waitForResult(true); + + for (ConnectionObserver observer : observers) { + observer.connectionFinished(compiler); + } + } catch (IOException e) { + e.printStackTrace(); + } catch (ClassNotFoundException e) { + throw new RuntimeException(e); + } finally { + if (socket != null) { + try { + socket.close(); + } catch (IOException e) { + } + } + } + } while (multiple); + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/server/Remote.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/server/Remote.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.runtime.server; + + +public interface Remote { + +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/server/ReplacingStreams.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/server/ReplacingStreams.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,228 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.max.graal.runtime.server; + +import java.io.*; +import java.lang.reflect.*; +import java.util.*; + +import com.oracle.max.graal.runtime.*; +import com.oracle.max.graal.runtime.Compiler; +import com.sun.cri.ci.*; + +public class ReplacingStreams { + + private IdentityHashMap objectMap = new IdentityHashMap(); + private ArrayList objectList = new ArrayList(); + + private ReplacingOutputStream output; + private ReplacingInputStream input; + + private InvocationSocket invocation; + + public ReplacingStreams(OutputStream outputStream, InputStream inputStream) throws IOException { + output = new ReplacingOutputStream(new BufferedOutputStream(outputStream)); + // required, because creating an ObjectOutputStream writes a header, but doesn't flush the stream + output.flush(); + input = new ReplacingInputStream(new BufferedInputStream(inputStream)); + invocation = new InvocationSocket(output, input); + + addStaticObject(CiValue.IllegalValue); + addStaticObject(HotSpotProxy.DUMMY_CONSTANT_OBJ); + } + + public void setInvocationSocket(InvocationSocket invocation) { + this.invocation = invocation; + } + + public ReplacingOutputStream getOutput() { + return output; + } + + public ReplacingInputStream getInput() { + return input; + } + + public InvocationSocket getInvocation() { + return invocation; + } + + private void addStaticObject(Object obj) { + int id = objectList.size(); + objectList.add(obj); + objectMap.put(obj, new Placeholder(id)); + } + + public static class Placeholder implements Serializable { + + public final int id; + + public Placeholder(int id) { + this.id = id; + } + + @Override + public String toString() { + return "#<" + id + ">"; + } + } + + public static class NewRemoteCallPlaceholder implements Serializable { + + public final Class[] interfaces; + + public NewRemoteCallPlaceholder(Class[] interfaces) { + this.interfaces = interfaces; + } + } + + public static class NewDummyPlaceholder implements Serializable { + } + + /** + * Replaces certain cir objects that cannot easily be made Serializable. + */ + public class ReplacingInputStream extends ObjectInputStream { + + private Compiler compiler; + + public ReplacingInputStream(InputStream in) throws IOException { + super(in); + enableResolveObject(true); + } + + public void setCompiler(Compiler compiler) { + this.compiler = compiler; + } + + @Override + protected Object resolveObject(Object obj) throws IOException { + // see ReplacingInputStream.replaceObject for details on when these types of objects are created + + if (obj instanceof Placeholder) { + Placeholder placeholder = (Placeholder) obj; + obj = objectList.get(placeholder.id); + return obj; + } + + if (obj instanceof NewRemoteCallPlaceholder) { + NewRemoteCallPlaceholder newPlaceholder = (NewRemoteCallPlaceholder) obj; + Placeholder placeholder = new Placeholder(objectList.size()); + obj = Proxy.newProxyInstance(getClass().getClassLoader(), newPlaceholder.interfaces, invocation.new Handler(placeholder)); + objectMap.put(obj, placeholder); + objectList.add(obj); + return obj; + } + + if (obj instanceof NewDummyPlaceholder) { + obj = new Placeholder(objectList.size()); + objectMap.put(obj, (Placeholder) obj); + objectList.add(obj); + return obj; + } + + return obj; + } + } + + /** + * Replaces certain cir objects that cannot easily be made Serializable. + */ + public class ReplacingOutputStream extends ObjectOutputStream { + + public ReplacingOutputStream(OutputStream out) throws IOException { + super(out); + enableReplaceObject(true); + } + + @Override + protected Object replaceObject(Object obj) throws IOException { + // is the object a known instance? + Placeholder placeholder = objectMap.get(obj); + if (placeholder != null) { + return placeholder; + } + + // is the object an instance of a class that will always be executed remotely? + if (obj instanceof Remote) { + return createRemoteCallPlaceholder(obj); + } + + // is the object a constant of object type? + if (obj.getClass() == CiConstant.class) { + CiConstant constant = (CiConstant) obj; + if (constant.kind != CiKind.Object) { + return obj; + } + Object contents = constant.asObject(); + if (contents == null) { + return obj; + } + // don't replace if the object already is a placeholder + if (contents instanceof Placeholder || contents instanceof Long) { + return obj; + } + placeholder = objectMap.get(contents); + if (placeholder != null) { + return CiConstant.forObject(placeholder); + } + if (contents instanceof Remote) { + return CiConstant.forObject(createRemoteCallPlaceholder(contents)); + } + return CiConstant.forObject(createDummyPlaceholder(contents)); + } + return obj; + } + } + + public static Class[] getAllInterfaces(Class clazz) { + HashSet> interfaces = new HashSet>(); + getAllInterfaces(clazz, interfaces); + return interfaces.toArray(new Class[interfaces.size()]); + } + + private static void getAllInterfaces(Class clazz, HashSet> interfaces) { + for (Class< ? > iface : clazz.getInterfaces()) { + if (!interfaces.contains(iface)) { + interfaces.add(iface); + getAllInterfaces(iface, interfaces); + } + } + if (clazz.getSuperclass() != null) { + getAllInterfaces(clazz.getSuperclass(), interfaces); + } + } + + private Object createRemoteCallPlaceholder(Object obj) { + // collect all interfaces that this object's class implements (proxies only support interfaces) + objectMap.put(obj, new Placeholder(objectList.size())); + objectList.add(obj); + return new NewRemoteCallPlaceholder(getAllInterfaces(obj.getClass())); + } + + public Object createDummyPlaceholder(Object obj) { + objectMap.put(obj, new Placeholder(objectList.size())); + objectList.add(obj); + return new NewDummyPlaceholder(); + } +} diff -r 810e2d253e00 -r d90bf514d647 graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/server/package-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/server/package-info.java Wed Jun 08 08:59:54 2011 +0200 @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +/** + * Implementation of a compilation server socket that delegates incoming requests to C1X. + * + * @author Lukas Stadler + * @author Thomas Wuerthinger + */ +package com.oracle.max.graal.runtime.server; diff -r 810e2d253e00 -r d90bf514d647 src/share/vm/c1x/c1x_Compiler.cpp --- a/src/share/vm/c1x/c1x_Compiler.cpp Wed Jun 08 08:45:47 2011 +0200 +++ b/src/share/vm/c1x/c1x_Compiler.cpp Wed Jun 08 08:59:54 2011 +0200 @@ -51,7 +51,7 @@ Runtime1::initialize(THREAD->get_buffer_blob()); JNIEnv *env = ((JavaThread *) Thread::current())->jni_environment(); - jclass klass = env->FindClass("com/oracle/graal/runtime/VMEntriesNative"); + jclass klass = env->FindClass("com/oracle/max/graal/runtime/VMEntriesNative"); if (klass == NULL) { tty->print_cr("c1x VMEntries class not found"); vm_abort(false); diff -r 810e2d253e00 -r d90bf514d647 src/share/vm/c1x/c1x_JavaAccess.hpp --- a/src/share/vm/c1x/c1x_JavaAccess.hpp Wed Jun 08 08:45:47 2011 +0200 +++ b/src/share/vm/c1x/c1x_JavaAccess.hpp Wed Jun 08 08:59:54 2011 +0200 @@ -46,7 +46,7 @@ #define COMPILER_CLASSES_DO(start_class, end_class, char_field, int_field, boolean_field, long_field, oop_field, static_oop_field) \ start_class(HotSpotTypeResolved) \ - oop_field(HotSpotTypeResolved, compiler, "Lcom/oracle/graal/runtime/Compiler;") \ + oop_field(HotSpotTypeResolved, compiler, "Lcom/oracle/max/graal/runtime/Compiler;") \ oop_field(HotSpotTypeResolved, javaMirror, "Ljava/lang/Class;") \ oop_field(HotSpotTypeResolved, simpleName, "Ljava/lang/String;") \ int_field(HotSpotTypeResolved, accessFlags) \ @@ -74,7 +74,7 @@ end_class \ start_class(HotSpotTargetMethod) \ oop_field(HotSpotTargetMethod, targetMethod, "Lcom/sun/cri/ci/CiTargetMethod;") \ - oop_field(HotSpotTargetMethod, method, "Lcom/oracle/graal/runtime/HotSpotMethodResolved;") \ + oop_field(HotSpotTargetMethod, method, "Lcom/oracle/max/graal/runtime/HotSpotMethodResolved;") \ oop_field(HotSpotTargetMethod, name, "Ljava/lang/String;") \ oop_field(HotSpotTargetMethod, sites, "[Lcom/sun/cri/ci/CiTargetMethod$Site;") \ oop_field(HotSpotTargetMethod, exceptionHandlers, "[Lcom/sun/cri/ci/CiTargetMethod$ExceptionHandler;") \ diff -r 810e2d253e00 -r d90bf514d647 src/share/vm/c1x/c1x_VMEntries.cpp --- a/src/share/vm/c1x/c1x_VMEntries.cpp Wed Jun 08 08:45:47 2011 +0200 +++ b/src/share/vm/c1x/c1x_VMEntries.cpp Wed Jun 08 08:59:54 2011 +0200 @@ -543,7 +543,7 @@ // public HotSpotVMConfig getConfiguration(); JNIEXPORT jobject JNICALL Java_com_oracle_graal_runtime_VMEntries_getConfiguration(JNIEnv *env, jobject) { - jclass klass = env->FindClass("com/oracle/graal/runtime/HotSpotVMConfig"); + jclass klass = env->FindClass("com/oracle/max/graal/runtime/HotSpotVMConfig"); assert(klass != NULL, "HotSpot vm config class not found"); jobject config = env->AllocObject(klass); #ifdef _WIN64 @@ -659,15 +659,15 @@ #define PROXY "J" #define TYPE "Lcom/sun/cri/ri/RiType;" -#define RESOLVED_TYPE "Lcom/oracle/graal/runtime/HotSpotTypeResolved;" +#define RESOLVED_TYPE "Lcom/oracle/max/graal/runtime/HotSpotTypeResolved;" #define METHOD "Lcom/sun/cri/ri/RiMethod;" #define SIGNATURE "Lcom/sun/cri/ri/RiSignature;" #define FIELD "Lcom/sun/cri/ri/RiField;" #define CONSTANT_POOL "Lcom/sun/cri/ri/RiConstantPool;" #define EXCEPTION_HANDLERS "[Lcom/sun/cri/ri/RiExceptionHandler;" -#define TARGET_METHOD "Lcom/oracle/graal/runtime/HotSpotTargetMethod;" -#define CONFIG "Lcom/oracle/graal/runtime/HotSpotVMConfig;" -#define HS_METHOD "Lcom/oracle/graal/runtime/HotSpotMethod;" +#define TARGET_METHOD "Lcom/oracle/max/graal/runtime/HotSpotTargetMethod;" +#define CONFIG "Lcom/oracle/max/graal/runtime/HotSpotVMConfig;" +#define HS_METHOD "Lcom/oracle/max/graal/runtime/HotSpotMethod;" #define CI_CONSTANT "Lcom/sun/cri/ci/CiConstant;" #define CI_KIND "Lcom/sun/cri/ci/CiKind;" #define STRING "Ljava/lang/String;" diff -r 810e2d253e00 -r d90bf514d647 src/share/vm/classfile/vmSymbols.hpp --- a/src/share/vm/classfile/vmSymbols.hpp Wed Jun 08 08:45:47 2011 +0200 +++ b/src/share/vm/classfile/vmSymbols.hpp Wed Jun 08 08:59:54 2011 +0200 @@ -258,18 +258,18 @@ LP64_ONLY( do_alias(machine_word_signature, long_signature) ) \ \ /* support for C1X */ \ - template(com_sun_hotspot_c1x_VMExits, "com/oracle/graal/runtime/VMExits") \ - template(com_sun_hotspot_c1x_HotSpotMethodResolved, "com/oracle/graal/runtime/HotSpotMethodResolved") \ - template(com_sun_hotspot_c1x_HotSpotTargetMethod, "com/oracle/graal/runtime/HotSpotTargetMethod") \ - template(com_sun_hotspot_c1x_HotSpotField, "com/oracle/graal/runtime/HotSpotField") \ + template(com_sun_hotspot_c1x_VMExits, "com/oracle/max/graal/runtime/VMExits") \ + template(com_sun_hotspot_c1x_HotSpotMethodResolved, "com/oracle/max/graal/runtime/HotSpotMethodResolved") \ + template(com_sun_hotspot_c1x_HotSpotTargetMethod, "com/oracle/max/graal/runtime/HotSpotTargetMethod") \ + template(com_sun_hotspot_c1x_HotSpotField, "com/oracle/max/graal/runtime/HotSpotField") \ template(com_sun_c1x_C1XOptions, "com/sun/c1x/C1XOptions") \ - template(com_sun_hotspot_c1x_HotSpotOptions, "com/oracle/graal/runtime/HotSpotOptions") \ - template(com_sun_hotspot_c1x_HotSpotTypeResolved, "com/oracle/graal/runtime/HotSpotTypeResolvedImpl") \ - template(com_sun_hotspot_c1x_HotSpotType, "com/oracle/graal/runtime/HotSpotType") \ - template(com_sun_hotspot_c1x_HotSpotExceptionHandler,"com/oracle/graal/runtime/HotSpotExceptionHandler") \ - template(com_sun_hotspot_c1x_HotSpotProxy, "com/oracle/graal/runtime/HotSpotProxy") \ - template(com_sun_hotspot_c1x_Compiler, "com/oracle/graal/runtime/Compiler") \ - template(com_sun_hotspot_c1x_CompilerImpl, "com/oracle/graal/runtime/CompilerImpl") \ + template(com_sun_hotspot_c1x_HotSpotOptions, "com/oracle/max/graal/runtime/HotSpotOptions") \ + template(com_sun_hotspot_c1x_HotSpotTypeResolved, "com/oracle/max/graal/runtime/HotSpotTypeResolvedImpl") \ + template(com_sun_hotspot_c1x_HotSpotType, "com/oracle/max/graal/runtime/HotSpotType") \ + template(com_sun_hotspot_c1x_HotSpotExceptionHandler,"com/oracle/max/graal/runtime/HotSpotExceptionHandler") \ + template(com_sun_hotspot_c1x_HotSpotProxy, "com/oracle/max/graal/runtime/HotSpotProxy") \ + template(com_sun_hotspot_c1x_Compiler, "com/oracle/max/graal/runtime/Compiler") \ + template(com_sun_hotspot_c1x_CompilerImpl, "com/oracle/max/graal/runtime/CompilerImpl") \ template(com_sun_cri_ri_RiMethod, "com/sun/cri/ri/RiMethod") \ template(com_sun_cri_ri_RiField, "com/sun/cri/ri/RiField") \ template(com_sun_cri_ri_RiType, "com/sun/cri/ri/RiType") \ @@ -326,10 +326,10 @@ template(createCiConstantObject_name, "createCiConstantObject") \ template(createCiConstantObject_signature, "(Ljava/lang/Object;)Lcom/sun/cri/ci/CiConstant;") \ template(getVMExits_name, "getVMExits") \ - template(getVMExits_signature, "()Lcom/oracle/graal/runtime/VMExits;") \ + template(getVMExits_signature, "()Lcom/oracle/max/graal/runtime/VMExits;") \ template(getInstance_name, "getInstance") \ template(initialize_name, "initialize") \ - template(getInstance_signature, "()Lcom/oracle/graal/runtime/Compiler;") \ + template(getInstance_signature, "()Lcom/oracle/max/graal/runtime/Compiler;") \ template(forObject_name, "forObject") \ \ /* common method and field names */ \ diff -r 810e2d253e00 -r d90bf514d647 src/share/vm/oops/klass.hpp --- a/src/share/vm/oops/klass.hpp Wed Jun 08 08:45:47 2011 +0200 +++ b/src/share/vm/oops/klass.hpp Wed Jun 08 08:59:54 2011 +0200 @@ -237,7 +237,7 @@ klassOop _primary_supers[_primary_super_limit]; // java/lang/Class instance mirroring this class oop _java_mirror; - // com/oracle/graal/runtime/HotSpotTypeResolved mirroring this class + // com/oracle/max/graal/runtime/HotSpotTypeResolved mirroring this class oop _c1x_mirror; // Superclass klassOop _super;