# HG changeset patch # User Christian Haeubl # Date 1354014918 -3600 # Node ID 32408bd16b91bda21878dfcca8019dcfdce62217 # Parent cd2c08049dd570fdeed8bf30b347ae79423fa84d fixes after merge diff -r cd2c08049dd5 -r 32408bd16b91 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java Tue Nov 27 12:12:02 2012 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java Tue Nov 27 12:15:18 2012 +0100 @@ -135,7 +135,7 @@ @Override public void run() { Assumptions assumptions = new Assumptions(GraalOptions.OptAssumptions); - SnippetInstaller installer = new SnippetInstaller(runtime, runtime.getGraalRuntime().getTarget(), HotSpotGraalRuntime.wordStamp(), assumptions); + SnippetInstaller installer = new SnippetInstaller(runtime, assumptions, runtime.getGraalRuntime().getTarget()); GraalIntrinsics.installIntrinsics(installer); runtime.installSnippets(installer, assumptions); } diff -r cd2c08049dd5 -r 32408bd16b91 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java Tue Nov 27 12:12:02 2012 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java Tue Nov 27 12:15:18 2012 +0100 @@ -1,751 +1,751 @@ -/* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 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.hotspot.meta; - -import static com.oracle.graal.api.code.DeoptimizationAction.*; -import static com.oracle.graal.api.code.MemoryBarriers.*; -import static com.oracle.graal.api.meta.DeoptimizationReason.*; -import static com.oracle.graal.api.meta.Value.*; -import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; -import static com.oracle.graal.hotspot.snippets.SystemSnippets.*; -import static com.oracle.graal.java.GraphBuilderPhase.*; -import static com.oracle.graal.nodes.StructuredGraph.*; -import static com.oracle.graal.nodes.UnwindNode.*; -import static com.oracle.graal.nodes.java.RegisterFinalizerNode.*; -import static com.oracle.graal.snippets.Log.*; -import static com.oracle.graal.snippets.MathSnippetsX86.*; - -import java.lang.reflect.*; -import java.util.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.code.CodeUtil.RefMapFormatter; -import com.oracle.graal.api.code.CompilationResult.Call; -import com.oracle.graal.api.code.CompilationResult.DataPatch; -import com.oracle.graal.api.code.CompilationResult.Mark; -import com.oracle.graal.api.code.CompilationResult.Safepoint; -import com.oracle.graal.api.code.Register.RegisterFlag; -import com.oracle.graal.api.code.RuntimeCall.Descriptor; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.hotspot.*; -import com.oracle.graal.hotspot.bridge.*; -import com.oracle.graal.hotspot.nodes.*; -import com.oracle.graal.hotspot.phases.*; -import com.oracle.graal.hotspot.snippets.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.calc.*; -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.nodes.java.*; -import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.type.*; -import com.oracle.graal.phases.*; -import com.oracle.graal.printer.*; -import com.oracle.graal.snippets.*; - -/** - * HotSpot implementation of {@link GraalCodeCacheProvider}. - */ -public abstract class HotSpotRuntime implements GraalCodeCacheProvider { - public final HotSpotVMConfig config; - - protected final RegisterConfig regConfig; - protected final RegisterConfig globalStubRegConfig; - protected final HotSpotGraalRuntime graalRuntime; - - private CheckCastSnippets.Templates checkcastSnippets; - private InstanceOfSnippets.Templates instanceofSnippets; - private NewObjectSnippets.Templates newObjectSnippets; - private MonitorSnippets.Templates monitorSnippets; - - private final Map runtimeCalls = new HashMap<>(); - - protected Value ret(Kind kind) { - if (kind.isVoid()) { - return ILLEGAL; - } - return globalStubRegConfig.getReturnRegister(kind).asValue(kind); - } - - protected Value arg(int index, Kind kind) { - if (kind.isFloat() || kind.isDouble()) { - return globalStubRegConfig.getCallingConventionRegisters(CallingConvention.Type.RuntimeCall, RegisterFlag.FPU)[index].asValue(kind); - } - return globalStubRegConfig.getCallingConventionRegisters(CallingConvention.Type.RuntimeCall, RegisterFlag.CPU)[index].asValue(kind); - } - - protected Value scratch(Kind kind) { - return globalStubRegConfig.getScratchRegister().asValue(kind); - } - - public HotSpotRuntime(HotSpotVMConfig config, HotSpotGraalRuntime graalRuntime) { - this.config = config; - this.graalRuntime = graalRuntime; - regConfig = createRegisterConfig(false); - globalStubRegConfig = createRegisterConfig(true); - - addRuntimeCall(UNWIND_EXCEPTION, config.unwindExceptionStub, - /* temps */ null, - /* ret */ ret(Kind.Void), - /* arg0: exception */ arg(0, Kind.Object)); - - addRuntimeCall(OnStackReplacementPhase.OSR_MIGRATION_END, config.osrMigrationEndStub, - /* temps */ null, - /* ret */ ret(Kind.Void), - /* arg0: long */ arg(0, Kind.Long)); - - addRuntimeCall(REGISTER_FINALIZER, config.registerFinalizerStub, - /* temps */ null, - /* ret */ ret(Kind.Void), - /* arg0: object */ arg(0, Kind.Object)); - - addRuntimeCall(CREATE_NULL_POINTER_EXCEPTION, config.createNullPointerExceptionStub, - /* temps */ null, - /* ret */ ret(Kind.Object)); - - addRuntimeCall(CREATE_OUT_OF_BOUNDS_EXCEPTION, config.createOutOfBoundsExceptionStub, - /* temps */ null, - /* ret */ ret(Kind.Object), - /* arg0: index */ arg(0, Kind.Int)); - - addRuntimeCall(JAVA_TIME_MILLIS, config.javaTimeMillisStub, - /* temps */ null, - /* ret */ ret(Kind.Long)); - - addRuntimeCall(JAVA_TIME_NANOS, config.javaTimeNanosStub, - /* temps */ null, - /* ret */ ret(Kind.Long)); - - addRuntimeCall(ARITHMETIC_SIN, config.arithmeticSinStub, - /* temps */ null, - /* ret */ ret(Kind.Double), - /* arg0: index */ arg(0, Kind.Double)); - - addRuntimeCall(ARITHMETIC_COS, config.arithmeticCosStub, - /* temps */ null, - /* ret */ ret(Kind.Double), - /* arg0: index */ arg(0, Kind.Double)); - - addRuntimeCall(ARITHMETIC_TAN, config.arithmeticTanStub, - /* temps */ null, - /* ret */ ret(Kind.Double), - /* arg0: index */ arg(0, Kind.Double)); - - addRuntimeCall(LOG_PRIMITIVE, config.logPrimitiveStub, - /* temps */ null, - /* ret */ ret(Kind.Void), - /* arg0: typeChar */ arg(0, Kind.Int), - /* arg1: value */ arg(1, Kind.Long), - /* arg2: newline */ arg(2, Kind.Boolean)); - - addRuntimeCall(LOG_PRINTF, config.logPrintfStub, - /* temps */ null, - /* ret */ ret(Kind.Void), - /* arg0: format */ arg(0, Kind.Object), - /* arg1: value */ arg(1, Kind.Long)); - - addRuntimeCall(LOG_OBJECT, config.logObjectStub, - /* temps */ null, - /* ret */ ret(Kind.Void), - /* arg0: object */ arg(0, Kind.Object), - /* arg1: flags */ arg(1, Kind.Int)); - } - - - /** - * Registers the details for linking a runtime call. - * - * @param descriptor name and signature of the call - * @param address target address of the call - * @param tempRegs temporary registers used (and killed) by the call (null if none) - * @param ret where the call returns its result - * @param args where arguments are passed to the call - */ - protected void addRuntimeCall(Descriptor descriptor, long address, Register[] tempRegs, Value ret, Value... args) { - Value[] temps = tempRegs == null || tempRegs.length == 0 ? Value.NONE : new Value[tempRegs.length]; - for (int i = 0; i < temps.length; i++) { - temps[i] = tempRegs[i].asValue(); - } - Kind retKind = ret.getKind(); - if (retKind == Kind.Illegal) { - retKind = Kind.Void; - } - assert retKind.equals(descriptor.getResultKind()) : descriptor + " incompatible with result location " + ret; - Kind[] argKinds = descriptor.getArgumentKinds(); - assert argKinds.length == args.length : descriptor + " incompatible with number of argument locations: " + args.length; - for (int i = 0; i < argKinds.length; i++) { - assert argKinds[i].equals(args[i].getKind()) : descriptor + " incompatible with argument location " + i + ": " + args[i]; - } - HotSpotRuntimeCall runtimeCall = new HotSpotRuntimeCall(descriptor, address, new CallingConvention(temps, 0, ret, args), graalRuntime.getCompilerToVM()); - runtimeCalls.put(descriptor, runtimeCall); - } - - protected abstract RegisterConfig createRegisterConfig(boolean globalStubConfig); - - public void installSnippets(SnippetInstaller installer, Assumptions assumptions) { - installer.install(SystemSnippets.class); - installer.install(UnsafeSnippets.class); - installer.install(ArrayCopySnippets.class); - - installer.install(CheckCastSnippets.class); - installer.install(InstanceOfSnippets.class); - installer.install(NewObjectSnippets.class); - installer.install(MonitorSnippets.class); - - checkcastSnippets = new CheckCastSnippets.Templates(this, assumptions, graalRuntime.getTarget()); - instanceofSnippets = new InstanceOfSnippets.Templates(this, assumptions, graalRuntime.getTarget()); - newObjectSnippets = new NewObjectSnippets.Templates(this, assumptions, graalRuntime.getTarget(), config.useTLAB); - monitorSnippets = new MonitorSnippets.Templates(this, assumptions, graalRuntime.getTarget(), config.useFastLocking); - } - - - public HotSpotGraalRuntime getGraalRuntime() { - return graalRuntime; - } - - /** - * Gets the register holding the current thread. - */ - public abstract Register threadRegister(); - - /** - * Gets the stack pointer register. - */ - public abstract Register stackPointerRegister(); - - @Override - public String disassemble(CodeInfo info, CompilationResult tm) { - byte[] code = info.getCode(); - TargetDescription target = graalRuntime.getTarget(); - HexCodeFile hcf = new HexCodeFile(code, info.getStart(), target.arch.getName(), target.wordSize * 8); - if (tm != null) { - HexCodeFile.addAnnotations(hcf, tm.getAnnotations()); - addExceptionHandlersComment(tm, hcf); - Register fp = regConfig.getFrameRegister(); - RefMapFormatter slotFormatter = new RefMapFormatter(target.arch, target.wordSize, fp, 0); - for (Safepoint safepoint : tm.getSafepoints()) { - if (safepoint instanceof Call) { - Call call = (Call) safepoint; - if (call.debugInfo != null) { - hcf.addComment(call.pcOffset + call.size, CodeUtil.append(new StringBuilder(100), call.debugInfo, slotFormatter).toString()); - } - addOperandComment(hcf, call.pcOffset, "{" + getTargetName(call) + "}"); - } else { - if (safepoint.debugInfo != null) { - hcf.addComment(safepoint.pcOffset, CodeUtil.append(new StringBuilder(100), safepoint.debugInfo, slotFormatter).toString()); - } - addOperandComment(hcf, safepoint.pcOffset, "{safepoint}"); - } - } - for (DataPatch site : tm.getDataReferences()) { - hcf.addOperandComment(site.pcOffset, "{" + site.constant + "}"); - } - for (Mark mark : tm.getMarks()) { - hcf.addComment(mark.pcOffset, getMarkName(mark)); - } - } - return hcf.toEmbeddedString(); - } - - /** - * Decodes a call target to a mnemonic if possible. - */ - private String getTargetName(Call call) { - Field[] fields = config.getClass().getDeclaredFields(); - for (Field f : fields) { - if (f.getName().endsWith("Stub")) { - f.setAccessible(true); - try { - Object address = f.get(config); - if (address.equals(call.target)) { - return f.getName() + ":0x" + Long.toHexString((Long) address); - } - } catch (Exception e) { - } - } - } - return String.valueOf(call.target); - } - - /** - * Decodes a mark to a mnemonic if possible. - */ - private static String getMarkName(Mark mark) { - Field[] fields = Marks.class.getDeclaredFields(); - for (Field f : fields) { - if (Modifier.isStatic(f.getModifiers()) && f.getName().startsWith("MARK_")) { - f.setAccessible(true); - try { - if (f.get(null).equals(mark.id)) { - return f.getName(); - } - } catch (Exception e) { - } - } - } - return "MARK:" + mark.id; - } - - private static void addExceptionHandlersComment(CompilationResult tm, HexCodeFile hcf) { - if (!tm.getExceptionHandlers().isEmpty()) { - String nl = HexCodeFile.NEW_LINE; - StringBuilder buf = new StringBuilder("------ Exception Handlers ------").append(nl); - for (CompilationResult.ExceptionHandler e : tm.getExceptionHandlers()) { - buf.append(" "). - append(e.pcOffset).append(" -> "). - append(e.handlerPos). - append(nl); - hcf.addComment(e.pcOffset, "[exception -> " + e.handlerPos + "]"); - hcf.addComment(e.handlerPos, "[exception handler for " + e.pcOffset + "]"); - } - hcf.addComment(0, buf.toString()); - } - } - - private static void addOperandComment(HexCodeFile hcf, int pos, String comment) { - String oldValue = hcf.addOperandComment(pos, comment); - assert oldValue == null : "multiple comments for operand of instruction at " + pos + ": " + comment + ", " + oldValue; - } - - @Override - public ResolvedJavaType lookupJavaType(Constant constant) { - if (!constant.getKind().isObject() || constant.isNull()) { - return null; - } - Object o = constant.asObject(); - return HotSpotResolvedJavaType.fromClass(o.getClass()); - } - - @Override - public int getSizeOfLockData() { - return config.basicLockSize; - } - - @Override - public boolean constantEquals(Constant x, Constant y) { - return x.equals(y); - } - - @Override - public RegisterConfig lookupRegisterConfig(JavaMethod 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 graalRuntime.getTarget().wordSize; - } - - @Override - public int getMinimumOutgoingSize() { - return config.runtimeCallStackSize; - } - - @Override - public int lookupArrayLength(Constant array) { - if (!array.getKind().isObject() || array.isNull() || !array.asObject().getClass().isArray()) { - throw new IllegalArgumentException(array + " is not an array"); - } - return Array.getLength(array.asObject()); - } - - @Override - public void lower(Node n, LoweringTool tool) { - StructuredGraph graph = (StructuredGraph) n.graph(); - Kind wordKind = graalRuntime.getTarget().wordKind; - if (n instanceof ArrayLengthNode) { - ArrayLengthNode arrayLengthNode = (ArrayLengthNode) n; - SafeReadNode safeReadArrayLength = safeReadArrayLength(arrayLengthNode.array(), StructuredGraph.INVALID_GRAPH_ID); - graph.replaceFixedWithFixed(arrayLengthNode, safeReadArrayLength); - } else if (n instanceof Invoke) { - Invoke invoke = (Invoke) n; - if (invoke.callTarget() instanceof MethodCallTargetNode) { - MethodCallTargetNode callTarget = invoke.methodCallTarget(); - NodeInputList parameters = callTarget.arguments(); - ValueNode receiver = parameters.size() <= 0 ? null : parameters.get(0); - if (!callTarget.isStatic() && receiver.kind() == Kind.Object && !receiver.objectStamp().nonNull()) { - invoke.node().dependencies().add(tool.createNullCheckGuard(receiver, invoke.leafGraphId())); - } - Kind[] signature = MetaUtil.signatureToKinds(callTarget.targetMethod().getSignature(), callTarget.isStatic() ? null : callTarget.targetMethod().getDeclaringClass().getKind()); - - AbstractCallTargetNode loweredCallTarget = null; - if (callTarget.invokeKind() == InvokeKind.Virtual && - GraalOptions.InlineVTableStubs && - (GraalOptions.AlwaysInlineVTableStubs || invoke.isPolymorphic())) { - - HotSpotResolvedJavaMethod hsMethod = (HotSpotResolvedJavaMethod) callTarget.targetMethod(); - if (!hsMethod.getDeclaringClass().isInterface()) { - int vtableEntryOffset = hsMethod.vtableEntryOffset(); - if (vtableEntryOffset > 0) { - // We use LocationNode.ANY_LOCATION for the reads that access the vtable entry and the compiled code entry - // as HotSpot does not guarantee they are final values. - assert vtableEntryOffset > 0; - LoadHubNode hub = graph.add(new LoadHubNode(receiver, wordKind)); - ReadNode metaspaceMethod = graph.add(new ReadNode(hub, LocationNode.create(LocationNode.ANY_LOCATION, wordKind, vtableEntryOffset, graph), StampFactory.forKind(wordKind()))); - ReadNode compiledEntry = graph.add(new ReadNode(metaspaceMethod, LocationNode.create(LocationNode.ANY_LOCATION, wordKind, config.methodCompiledEntryOffset, graph), StampFactory.forKind(wordKind()))); - - loweredCallTarget = graph.add(new HotSpotIndirectCallTargetNode(metaspaceMethod, compiledEntry, parameters, invoke.node().stamp(), signature, callTarget.targetMethod(), CallingConvention.Type.JavaCall)); - - graph.addBeforeFixed(invoke.node(), hub); - graph.addAfterFixed(hub, metaspaceMethod); - graph.addAfterFixed(metaspaceMethod, compiledEntry); - } - } - } - - if (loweredCallTarget == null) { - loweredCallTarget = graph.add(new HotSpotDirectCallTargetNode(parameters, invoke.node().stamp(), signature, callTarget.targetMethod(), CallingConvention.Type.JavaCall, callTarget.invokeKind())); - } - callTarget.replaceAndDelete(loweredCallTarget); - } - } else if (n instanceof LoadFieldNode) { - LoadFieldNode field = (LoadFieldNode) n; - int displacement = ((HotSpotResolvedJavaField) field.field()).offset(); - assert field.kind() != Kind.Illegal; - ReadNode memoryRead = graph.add(new ReadNode(field.object(), LocationNode.create(field.field(), field.field().getKind(), displacement, graph), field.stamp())); - memoryRead.dependencies().add(tool.createNullCheckGuard(field.object(), field.leafGraphId())); - graph.replaceFixedWithFixed(field, memoryRead); - if (field.isVolatile()) { - MembarNode preMembar = graph.add(new MembarNode(JMM_PRE_VOLATILE_READ)); - graph.addBeforeFixed(memoryRead, preMembar); - MembarNode postMembar = graph.add(new MembarNode(JMM_POST_VOLATILE_READ)); - graph.addAfterFixed(memoryRead, postMembar); - } - } else if (n instanceof StoreFieldNode) { - StoreFieldNode storeField = (StoreFieldNode) n; - HotSpotResolvedJavaField field = (HotSpotResolvedJavaField) storeField.field(); - WriteNode memoryWrite = graph.add(new WriteNode(storeField.object(), storeField.value(), LocationNode.create(field, field.getKind(), field.offset(), graph))); - memoryWrite.dependencies().add(tool.createNullCheckGuard(storeField.object(), storeField.leafGraphId())); - memoryWrite.setStateAfter(storeField.stateAfter()); - graph.replaceFixedWithFixed(storeField, memoryWrite); - FixedWithNextNode last = memoryWrite; - if (field.getKind() == Kind.Object && !memoryWrite.value().objectStamp().alwaysNull()) { - FieldWriteBarrier writeBarrier = graph.add(new FieldWriteBarrier(memoryWrite.object())); - graph.addAfterFixed(memoryWrite, writeBarrier); - last = writeBarrier; - } - if (storeField.isVolatile()) { - MembarNode preMembar = graph.add(new MembarNode(JMM_PRE_VOLATILE_WRITE)); - graph.addBeforeFixed(memoryWrite, preMembar); - MembarNode postMembar = graph.add(new MembarNode(JMM_POST_VOLATILE_WRITE)); - graph.addAfterFixed(last, postMembar); - } - } else if (n instanceof CompareAndSwapNode) { - // Separate out GC barrier semantics - CompareAndSwapNode cas = (CompareAndSwapNode) n; - ValueNode expected = cas.expected(); - if (expected.kind() == Kind.Object && !cas.newValue().objectStamp().alwaysNull()) { - ResolvedJavaType type = cas.object().objectStamp().type(); - if (type != null && !type.isArrayClass() && type.toJava() != Object.class) { - // Use a field write barrier since it's not an array store - FieldWriteBarrier writeBarrier = graph.add(new FieldWriteBarrier(cas.object())); - graph.addAfterFixed(cas, writeBarrier); - } else { - // This may be an array store so use an array write barrier - LocationNode location = IndexedLocationNode.create(LocationNode.ANY_LOCATION, cas.expected().kind(), cas.displacement(), cas.offset(), graph, false); - graph.addAfterFixed(cas, graph.add(new ArrayWriteBarrier(cas.object(), location))); - } - } - } else if (n instanceof LoadIndexedNode) { - LoadIndexedNode loadIndexed = (LoadIndexedNode) n; - ValueNode boundsCheck = createBoundsCheck(loadIndexed, tool); - Kind elementKind = loadIndexed.elementKind(); - LocationNode arrayLocation = createArrayLocation(graph, elementKind, loadIndexed.index()); - ReadNode memoryRead = graph.add(new ReadNode(loadIndexed.array(), arrayLocation, loadIndexed.stamp())); - memoryRead.dependencies().add(boundsCheck); - graph.replaceFixedWithFixed(loadIndexed, memoryRead); - } else if (n instanceof StoreIndexedNode) { - StoreIndexedNode storeIndexed = (StoreIndexedNode) n; - ValueNode boundsCheck = createBoundsCheck(storeIndexed, tool); - - Kind elementKind = storeIndexed.elementKind(); - LocationNode arrayLocation = createArrayLocation(graph, elementKind, storeIndexed.index()); - ValueNode value = storeIndexed.value(); - ValueNode array = storeIndexed.array(); - if (elementKind == Kind.Object && !value.objectStamp().alwaysNull()) { - // Store check! - ResolvedJavaType arrayType = array.objectStamp().type(); - if (arrayType != null && array.objectStamp().isExactType()) { - ResolvedJavaType elementType = arrayType.getComponentType(); - if (!MetaUtil.isJavaLangObject(elementType)) { - CheckCastNode checkcast = graph.add(new CheckCastNode(elementType, value, null)); - graph.addBeforeFixed(storeIndexed, checkcast); - value = checkcast; - } - } else { - LoadHubNode arrayClass = graph.add(new LoadHubNode(array, wordKind)); - LocationNode location = LocationNode.create(LocationNode.FINAL_LOCATION, wordKind, config.arrayClassElementOffset, graph); - FloatingReadNode arrayElementKlass = graph.unique(new FloatingReadNode(arrayClass, location, null, StampFactory.forKind(wordKind()))); - CheckCastDynamicNode checkcast = graph.add(new CheckCastDynamicNode(arrayElementKlass, value)); - graph.addBeforeFixed(storeIndexed, checkcast); - graph.addBeforeFixed(checkcast, arrayClass); - value = checkcast; - } - } - WriteNode memoryWrite = graph.add(new WriteNode(array, value, arrayLocation)); - memoryWrite.dependencies().add(boundsCheck); - memoryWrite.setStateAfter(storeIndexed.stateAfter()); - - graph.replaceFixedWithFixed(storeIndexed, memoryWrite); - - if (elementKind == Kind.Object && !value.objectStamp().alwaysNull()) { - graph.addAfterFixed(memoryWrite, graph.add(new ArrayWriteBarrier(array, arrayLocation))); - } - } else if (n instanceof UnsafeLoadNode) { - UnsafeLoadNode load = (UnsafeLoadNode) n; - assert load.kind() != Kind.Illegal; - IndexedLocationNode location = IndexedLocationNode.create(LocationNode.ANY_LOCATION, load.loadKind(), load.displacement(), load.offset(), graph, false); - ReadNode memoryRead = graph.add(new ReadNode(load.object(), location, load.stamp())); - // An unsafe read must not floating outside its block as may float above an explicit null check on its object. - memoryRead.dependencies().add(BeginNode.prevBegin(load)); - graph.replaceFixedWithFixed(load, memoryRead); - } else if (n instanceof UnsafeStoreNode) { - UnsafeStoreNode store = (UnsafeStoreNode) n; - IndexedLocationNode location = IndexedLocationNode.create(LocationNode.ANY_LOCATION, store.storeKind(), store.displacement(), store.offset(), graph, false); - ValueNode object = store.object(); - WriteNode write = graph.add(new WriteNode(object, store.value(), location)); - write.setStateAfter(store.stateAfter()); - graph.replaceFixedWithFixed(store, write); - if (write.value().kind() == Kind.Object && !write.value().objectStamp().alwaysNull()) { - ResolvedJavaType type = object.objectStamp().type(); - WriteBarrier writeBarrier; - if (type != null && !type.isArrayClass() && type.toJava() != Object.class) { - // Use a field write barrier since it's not an array store - writeBarrier = graph.add(new FieldWriteBarrier(object)); - } else { - // This may be an array store so use an array write barrier - writeBarrier = graph.add(new ArrayWriteBarrier(object, location)); - } - graph.addAfterFixed(write, writeBarrier); - } - } else if (n instanceof LoadHubNode) { - LoadHubNode loadHub = (LoadHubNode) n; - assert loadHub.kind() == wordKind; - LocationNode location = LocationNode.create(LocationNode.FINAL_LOCATION, wordKind, config.hubOffset, graph); - ValueNode object = loadHub.object(); - assert !object.isConstant(); - ValueNode guard = tool.createNullCheckGuard(object, StructuredGraph.INVALID_GRAPH_ID); - ReadNode hub = graph.add(new ReadNode(object, location, StampFactory.forKind(wordKind()))); - hub.dependencies().add(guard); - graph.replaceFixed(loadHub, hub); - } else if (n instanceof CheckCastNode) { - checkcastSnippets.lower((CheckCastNode) n, tool); - } else if (n instanceof CheckCastDynamicNode) { - checkcastSnippets.lower((CheckCastDynamicNode) n); - } else if (n instanceof InstanceOfNode) { - instanceofSnippets.lower((InstanceOfNode) n, tool); - } else if (n instanceof NewInstanceNode) { - newObjectSnippets.lower((NewInstanceNode) n, tool); - } else if (n instanceof NewArrayNode) { - newObjectSnippets.lower((NewArrayNode) n, tool); - } else if (n instanceof MonitorEnterNode) { - monitorSnippets.lower((MonitorEnterNode) n, tool); - } else if (n instanceof MonitorExitNode) { - monitorSnippets.lower((MonitorExitNode) n, tool); - } else if (n instanceof TLABAllocateNode) { - newObjectSnippets.lower((TLABAllocateNode) n, tool); - } else if (n instanceof InitializeObjectNode) { - newObjectSnippets.lower((InitializeObjectNode) n, tool); - } else if (n instanceof InitializeArrayNode) { - newObjectSnippets.lower((InitializeArrayNode) n, tool); - } else if (n instanceof NewMultiArrayNode) { - newObjectSnippets.lower((NewMultiArrayNode) n, tool); - } else { - assert false : "Node implementing Lowerable not handled: " + n; - throw GraalInternalError.shouldNotReachHere(); - } - } - - private static IndexedLocationNode createArrayLocation(Graph graph, Kind elementKind, ValueNode index) { - return IndexedLocationNode.create(LocationNode.getArrayLocation(elementKind), elementKind, elementKind.getArrayBaseOffset(), index, graph, true); - } - - private SafeReadNode safeReadArrayLength(ValueNode array, long leafGraphId) { - return safeRead(array.graph(), Kind.Int, array, config.arrayLengthOffset, StampFactory.positiveInt(), leafGraphId); - } - - private static ValueNode createBoundsCheck(AccessIndexedNode n, LoweringTool tool) { - StructuredGraph graph = (StructuredGraph) n.graph(); - ArrayLengthNode arrayLength = graph.add(new ArrayLengthNode(n.array())); - ValueNode guard = tool.createGuard(graph.unique(new IntegerBelowThanNode(n.index(), arrayLength)), BoundsCheckException, InvalidateReprofile, n.leafGraphId()); - - graph.addBeforeFixed(n, arrayLength); - return guard; - } - - @Override - public StructuredGraph intrinsicGraph(ResolvedJavaMethod caller, int bci, ResolvedJavaMethod method, List parameters) { - ResolvedJavaType holder = method.getDeclaringClass(); - String fullName = method.getName() + ((HotSpotSignature) method.getSignature()).asString(); - Kind wordKind = graalRuntime.getTarget().wordKind; - if (holder.toJava() == Object.class) { - if (fullName.equals("getClass()Ljava/lang/Class;")) { - ValueNode obj = (ValueNode) parameters.get(0); - ObjectStamp stamp = (ObjectStamp) obj.stamp(); - if (stamp.nonNull() && stamp.isExactType()) { - StructuredGraph graph = new StructuredGraph(); - ValueNode result = ConstantNode.forObject(stamp.type().toJava(), this, graph); - ReturnNode ret = graph.add(new ReturnNode(result)); - graph.start().setNext(ret); - return graph; - } - StructuredGraph graph = new StructuredGraph(); - LocalNode receiver = graph.unique(new LocalNode(0, StampFactory.objectNonNull())); - LoadHubNode hub = graph.add(new LoadHubNode(receiver, wordKind)); - Stamp resultStamp = StampFactory.declaredNonNull(lookupJavaType(Class.class)); - FloatingReadNode result = graph.unique(new FloatingReadNode(hub, LocationNode.create(LocationNode.FINAL_LOCATION, Kind.Object, config.classMirrorOffset, graph), null, resultStamp)); - ReturnNode ret = graph.add(new ReturnNode(result)); - graph.start().setNext(hub); - hub.setNext(ret); - return graph; - } - } else if (holder.toJava() == Class.class) { - if (fullName.equals("getModifiers()I")) { - StructuredGraph graph = new StructuredGraph(); - LocalNode receiver = graph.unique(new LocalNode(0, StampFactory.objectNonNull())); - SafeReadNode klass = safeRead(graph, wordKind, receiver, config.klassOffset, StampFactory.forKind(wordKind), INVALID_GRAPH_ID); - graph.start().setNext(klass); - LocationNode location = LocationNode.create(LocationNode.FINAL_LOCATION, Kind.Int, config.klassModifierFlagsOffset, graph); - FloatingReadNode readModifiers = graph.unique(new FloatingReadNode(klass, location, null, StampFactory.intValue())); - CompareNode isZero = CompareNode.createCompareNode(Condition.EQ, klass, ConstantNode.defaultForKind(wordKind, graph)); - GuardNode guard = graph.unique(new GuardNode(isZero, graph.start(), NullCheckException, InvalidateReprofile, true, INVALID_GRAPH_ID)); - readModifiers.dependencies().add(guard); - ReturnNode ret = graph.add(new ReturnNode(readModifiers)); - klass.setNext(ret); - return graph; - } - } else if (holder.toJava() == Thread.class) { - if (fullName.equals("currentThread()Ljava/lang/Thread;")) { - StructuredGraph graph = new StructuredGraph(); - ReturnNode ret = graph.add(new ReturnNode(graph.unique(new CurrentThread(config.threadObjectOffset, this)))); - graph.start().setNext(ret); - return graph; - } - } - return null; - } - - private static SafeReadNode safeRead(Graph graph, Kind kind, ValueNode value, int offset, Stamp stamp, long leafGraphId) { - return graph.add(new SafeReadNode(value, LocationNode.create(LocationNode.FINAL_LOCATION, kind, offset, graph), stamp, leafGraphId)); - } - - public ResolvedJavaType lookupJavaType(Class clazz) { - return HotSpotResolvedJavaType.fromClass(clazz); - } - - public Object lookupCallTarget(Object target) { - if (target instanceof HotSpotRuntimeCall) { - return ((HotSpotRuntimeCall) target).address; - } - return target; - } - - public RuntimeCall lookupRuntimeCall(Descriptor descriptor) { - assert runtimeCalls.containsKey(descriptor) : descriptor; - return runtimeCalls.get(descriptor); - } - - public ResolvedJavaMethod lookupJavaMethod(Method reflectionMethod) { - CompilerToVM c2vm = graalRuntime.getCompilerToVM(); - HotSpotResolvedJavaType[] resultHolder = {null}; - long metaspaceMethod = c2vm.getMetaspaceMethod(reflectionMethod, resultHolder); - assert metaspaceMethod != 0L; - return resultHolder[0].createMethod(metaspaceMethod); - } - - @Override - public ResolvedJavaField lookupJavaField(Field reflectionField) { - return graalRuntime.getCompilerToVM().getJavaField(reflectionField); - } - - private static HotSpotCodeInfo makeInfo(ResolvedJavaMethod method, CompilationResult compResult, CodeInfo[] info) { - HotSpotCodeInfo hsInfo = null; - if (info != null && info.length > 0) { - hsInfo = new HotSpotCodeInfo(compResult, (HotSpotResolvedJavaMethod) method); - info[0] = hsInfo; - } - return hsInfo; - } - - public void installMethod(HotSpotResolvedJavaMethod method, int entryBCI, CompilationResult compResult, CodeInfo[] info) { - HotSpotCodeInfo hsInfo = makeInfo(method, compResult, info); - graalRuntime.getCompilerToVM().installCode(new HotSpotCompilationResult(method, entryBCI, compResult), null, hsInfo); - } - - @Override - public InstalledCode addMethod(ResolvedJavaMethod method, CompilationResult compResult, CodeInfo[] info) { - HotSpotCodeInfo hsInfo = makeInfo(method, compResult, info); - HotSpotResolvedJavaMethod hotspotMethod = (HotSpotResolvedJavaMethod) method; - return graalRuntime.getCompilerToVM().installCode(new HotSpotCompilationResult(hotspotMethod, -1, compResult), new HotSpotInstalledCode(hotspotMethod), hsInfo); - } - - @Override - public int encodeDeoptActionAndReason(DeoptimizationAction action, DeoptimizationReason reason) { - final int actionShift = 0; - final int reasonShift = 3; - - int actionValue = convertDeoptAction(action); - int reasonValue = convertDeoptReason(reason); - return (~(((reasonValue) << reasonShift) + ((actionValue) << actionShift))); - } - - public int convertDeoptAction(DeoptimizationAction action) { - // This must be kept in sync with the DeoptAction enum defined in deoptimization.hpp - switch(action) { - case None: return 0; - case RecompileIfTooManyDeopts: return 1; - case InvalidateReprofile: return 2; - case InvalidateRecompile: return 3; - case InvalidateStopCompiling: return 4; - default: throw GraalInternalError.shouldNotReachHere(); - } - } - - public int convertDeoptReason(DeoptimizationReason reason) { - // This must be kept in sync with the DeoptReason enum defined in deoptimization.hpp - switch(reason) { - case None: return 0; - case NullCheckException: return 1; - case BoundsCheckException: return 2; - case ClassCastException: return 3; - case ArrayStoreException: return 4; - case UnreachedCode: return 5; - case TypeCheckedInliningViolated: return 6; - case OptimizedTypeCheckViolated: return 7; - case NotCompiledExceptionHandler: return 8; - case Unresolved: return 9; - case JavaSubroutineMismatch: return 10; - case ArithmeticException: return 11; - case RuntimeConstraint: return 12; - default: throw GraalInternalError.shouldNotReachHere(); - } - } - - public boolean needsDataPatch(Constant constant) { - return constant.getPrimitiveAnnotation() instanceof HotSpotResolvedJavaType; - } -} +/* + * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 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.hotspot.meta; + +import static com.oracle.graal.api.code.DeoptimizationAction.*; +import static com.oracle.graal.api.code.MemoryBarriers.*; +import static com.oracle.graal.api.meta.DeoptimizationReason.*; +import static com.oracle.graal.api.meta.Value.*; +import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; +import static com.oracle.graal.hotspot.snippets.SystemSnippets.*; +import static com.oracle.graal.java.GraphBuilderPhase.*; +import static com.oracle.graal.nodes.StructuredGraph.*; +import static com.oracle.graal.nodes.UnwindNode.*; +import static com.oracle.graal.nodes.java.RegisterFinalizerNode.*; +import static com.oracle.graal.snippets.Log.*; +import static com.oracle.graal.snippets.MathSnippetsX86.*; + +import java.lang.reflect.*; +import java.util.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.code.CodeUtil.RefMapFormatter; +import com.oracle.graal.api.code.CompilationResult.Call; +import com.oracle.graal.api.code.CompilationResult.DataPatch; +import com.oracle.graal.api.code.CompilationResult.Mark; +import com.oracle.graal.api.code.CompilationResult.Safepoint; +import com.oracle.graal.api.code.Register.RegisterFlag; +import com.oracle.graal.api.code.RuntimeCall.Descriptor; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.hotspot.*; +import com.oracle.graal.hotspot.bridge.*; +import com.oracle.graal.hotspot.nodes.*; +import com.oracle.graal.hotspot.phases.*; +import com.oracle.graal.hotspot.snippets.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; +import com.oracle.graal.phases.*; +import com.oracle.graal.printer.*; +import com.oracle.graal.snippets.*; + +/** + * HotSpot implementation of {@link GraalCodeCacheProvider}. + */ +public abstract class HotSpotRuntime implements GraalCodeCacheProvider { + public final HotSpotVMConfig config; + + protected final RegisterConfig regConfig; + protected final RegisterConfig globalStubRegConfig; + protected final HotSpotGraalRuntime graalRuntime; + + private CheckCastSnippets.Templates checkcastSnippets; + private InstanceOfSnippets.Templates instanceofSnippets; + private NewObjectSnippets.Templates newObjectSnippets; + private MonitorSnippets.Templates monitorSnippets; + + private final Map runtimeCalls = new HashMap<>(); + + protected Value ret(Kind kind) { + if (kind.isVoid()) { + return ILLEGAL; + } + return globalStubRegConfig.getReturnRegister(kind).asValue(kind); + } + + protected Value arg(int index, Kind kind) { + if (kind.isFloat() || kind.isDouble()) { + return globalStubRegConfig.getCallingConventionRegisters(CallingConvention.Type.RuntimeCall, RegisterFlag.FPU)[index].asValue(kind); + } + return globalStubRegConfig.getCallingConventionRegisters(CallingConvention.Type.RuntimeCall, RegisterFlag.CPU)[index].asValue(kind); + } + + protected Value scratch(Kind kind) { + return globalStubRegConfig.getScratchRegister().asValue(kind); + } + + public HotSpotRuntime(HotSpotVMConfig config, HotSpotGraalRuntime graalRuntime) { + this.config = config; + this.graalRuntime = graalRuntime; + regConfig = createRegisterConfig(false); + globalStubRegConfig = createRegisterConfig(true); + + addRuntimeCall(UNWIND_EXCEPTION, config.unwindExceptionStub, + /* temps */ null, + /* ret */ ret(Kind.Void), + /* arg0: exception */ arg(0, Kind.Object)); + + addRuntimeCall(OnStackReplacementPhase.OSR_MIGRATION_END, config.osrMigrationEndStub, + /* temps */ null, + /* ret */ ret(Kind.Void), + /* arg0: long */ arg(0, Kind.Long)); + + addRuntimeCall(REGISTER_FINALIZER, config.registerFinalizerStub, + /* temps */ null, + /* ret */ ret(Kind.Void), + /* arg0: object */ arg(0, Kind.Object)); + + addRuntimeCall(CREATE_NULL_POINTER_EXCEPTION, config.createNullPointerExceptionStub, + /* temps */ null, + /* ret */ ret(Kind.Object)); + + addRuntimeCall(CREATE_OUT_OF_BOUNDS_EXCEPTION, config.createOutOfBoundsExceptionStub, + /* temps */ null, + /* ret */ ret(Kind.Object), + /* arg0: index */ arg(0, Kind.Int)); + + addRuntimeCall(JAVA_TIME_MILLIS, config.javaTimeMillisStub, + /* temps */ null, + /* ret */ ret(Kind.Long)); + + addRuntimeCall(JAVA_TIME_NANOS, config.javaTimeNanosStub, + /* temps */ null, + /* ret */ ret(Kind.Long)); + + addRuntimeCall(ARITHMETIC_SIN, config.arithmeticSinStub, + /* temps */ null, + /* ret */ ret(Kind.Double), + /* arg0: index */ arg(0, Kind.Double)); + + addRuntimeCall(ARITHMETIC_COS, config.arithmeticCosStub, + /* temps */ null, + /* ret */ ret(Kind.Double), + /* arg0: index */ arg(0, Kind.Double)); + + addRuntimeCall(ARITHMETIC_TAN, config.arithmeticTanStub, + /* temps */ null, + /* ret */ ret(Kind.Double), + /* arg0: index */ arg(0, Kind.Double)); + + addRuntimeCall(LOG_PRIMITIVE, config.logPrimitiveStub, + /* temps */ null, + /* ret */ ret(Kind.Void), + /* arg0: typeChar */ arg(0, Kind.Int), + /* arg1: value */ arg(1, Kind.Long), + /* arg2: newline */ arg(2, Kind.Boolean)); + + addRuntimeCall(LOG_PRINTF, config.logPrintfStub, + /* temps */ null, + /* ret */ ret(Kind.Void), + /* arg0: format */ arg(0, Kind.Object), + /* arg1: value */ arg(1, Kind.Long)); + + addRuntimeCall(LOG_OBJECT, config.logObjectStub, + /* temps */ null, + /* ret */ ret(Kind.Void), + /* arg0: object */ arg(0, Kind.Object), + /* arg1: flags */ arg(1, Kind.Int)); + } + + + /** + * Registers the details for linking a runtime call. + * + * @param descriptor name and signature of the call + * @param address target address of the call + * @param tempRegs temporary registers used (and killed) by the call (null if none) + * @param ret where the call returns its result + * @param args where arguments are passed to the call + */ + protected void addRuntimeCall(Descriptor descriptor, long address, Register[] tempRegs, Value ret, Value... args) { + Value[] temps = tempRegs == null || tempRegs.length == 0 ? Value.NONE : new Value[tempRegs.length]; + for (int i = 0; i < temps.length; i++) { + temps[i] = tempRegs[i].asValue(); + } + Kind retKind = ret.getKind(); + if (retKind == Kind.Illegal) { + retKind = Kind.Void; + } + assert retKind.equals(descriptor.getResultKind()) : descriptor + " incompatible with result location " + ret; + Kind[] argKinds = descriptor.getArgumentKinds(); + assert argKinds.length == args.length : descriptor + " incompatible with number of argument locations: " + args.length; + for (int i = 0; i < argKinds.length; i++) { + assert argKinds[i].equals(args[i].getKind()) : descriptor + " incompatible with argument location " + i + ": " + args[i]; + } + HotSpotRuntimeCall runtimeCall = new HotSpotRuntimeCall(descriptor, address, new CallingConvention(temps, 0, ret, args), graalRuntime.getCompilerToVM()); + runtimeCalls.put(descriptor, runtimeCall); + } + + protected abstract RegisterConfig createRegisterConfig(boolean globalStubConfig); + + public void installSnippets(SnippetInstaller installer, Assumptions assumptions) { + installer.install(SystemSnippets.class); + installer.install(UnsafeSnippets.class); + installer.install(ArrayCopySnippets.class); + + installer.install(CheckCastSnippets.class); + installer.install(InstanceOfSnippets.class); + installer.install(NewObjectSnippets.class); + installer.install(MonitorSnippets.class); + + checkcastSnippets = new CheckCastSnippets.Templates(this, assumptions, graalRuntime.getTarget()); + instanceofSnippets = new InstanceOfSnippets.Templates(this, assumptions, graalRuntime.getTarget()); + newObjectSnippets = new NewObjectSnippets.Templates(this, assumptions, graalRuntime.getTarget(), config.useTLAB); + monitorSnippets = new MonitorSnippets.Templates(this, assumptions, graalRuntime.getTarget(), config.useFastLocking); + } + + + public HotSpotGraalRuntime getGraalRuntime() { + return graalRuntime; + } + + /** + * Gets the register holding the current thread. + */ + public abstract Register threadRegister(); + + /** + * Gets the stack pointer register. + */ + public abstract Register stackPointerRegister(); + + @Override + public String disassemble(CodeInfo info, CompilationResult tm) { + byte[] code = info.getCode(); + TargetDescription target = graalRuntime.getTarget(); + HexCodeFile hcf = new HexCodeFile(code, info.getStart(), target.arch.getName(), target.wordSize * 8); + if (tm != null) { + HexCodeFile.addAnnotations(hcf, tm.getAnnotations()); + addExceptionHandlersComment(tm, hcf); + Register fp = regConfig.getFrameRegister(); + RefMapFormatter slotFormatter = new RefMapFormatter(target.arch, target.wordSize, fp, 0); + for (Safepoint safepoint : tm.getSafepoints()) { + if (safepoint instanceof Call) { + Call call = (Call) safepoint; + if (call.debugInfo != null) { + hcf.addComment(call.pcOffset + call.size, CodeUtil.append(new StringBuilder(100), call.debugInfo, slotFormatter).toString()); + } + addOperandComment(hcf, call.pcOffset, "{" + getTargetName(call) + "}"); + } else { + if (safepoint.debugInfo != null) { + hcf.addComment(safepoint.pcOffset, CodeUtil.append(new StringBuilder(100), safepoint.debugInfo, slotFormatter).toString()); + } + addOperandComment(hcf, safepoint.pcOffset, "{safepoint}"); + } + } + for (DataPatch site : tm.getDataReferences()) { + hcf.addOperandComment(site.pcOffset, "{" + site.constant + "}"); + } + for (Mark mark : tm.getMarks()) { + hcf.addComment(mark.pcOffset, getMarkName(mark)); + } + } + return hcf.toEmbeddedString(); + } + + /** + * Decodes a call target to a mnemonic if possible. + */ + private String getTargetName(Call call) { + Field[] fields = config.getClass().getDeclaredFields(); + for (Field f : fields) { + if (f.getName().endsWith("Stub")) { + f.setAccessible(true); + try { + Object address = f.get(config); + if (address.equals(call.target)) { + return f.getName() + ":0x" + Long.toHexString((Long) address); + } + } catch (Exception e) { + } + } + } + return String.valueOf(call.target); + } + + /** + * Decodes a mark to a mnemonic if possible. + */ + private static String getMarkName(Mark mark) { + Field[] fields = Marks.class.getDeclaredFields(); + for (Field f : fields) { + if (Modifier.isStatic(f.getModifiers()) && f.getName().startsWith("MARK_")) { + f.setAccessible(true); + try { + if (f.get(null).equals(mark.id)) { + return f.getName(); + } + } catch (Exception e) { + } + } + } + return "MARK:" + mark.id; + } + + private static void addExceptionHandlersComment(CompilationResult tm, HexCodeFile hcf) { + if (!tm.getExceptionHandlers().isEmpty()) { + String nl = HexCodeFile.NEW_LINE; + StringBuilder buf = new StringBuilder("------ Exception Handlers ------").append(nl); + for (CompilationResult.ExceptionHandler e : tm.getExceptionHandlers()) { + buf.append(" "). + append(e.pcOffset).append(" -> "). + append(e.handlerPos). + append(nl); + hcf.addComment(e.pcOffset, "[exception -> " + e.handlerPos + "]"); + hcf.addComment(e.handlerPos, "[exception handler for " + e.pcOffset + "]"); + } + hcf.addComment(0, buf.toString()); + } + } + + private static void addOperandComment(HexCodeFile hcf, int pos, String comment) { + String oldValue = hcf.addOperandComment(pos, comment); + assert oldValue == null : "multiple comments for operand of instruction at " + pos + ": " + comment + ", " + oldValue; + } + + @Override + public ResolvedJavaType lookupJavaType(Constant constant) { + if (!constant.getKind().isObject() || constant.isNull()) { + return null; + } + Object o = constant.asObject(); + return HotSpotResolvedJavaType.fromClass(o.getClass()); + } + + @Override + public int getSizeOfLockData() { + return config.basicLockSize; + } + + @Override + public boolean constantEquals(Constant x, Constant y) { + return x.equals(y); + } + + @Override + public RegisterConfig lookupRegisterConfig(JavaMethod 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 graalRuntime.getTarget().wordSize; + } + + @Override + public int getMinimumOutgoingSize() { + return config.runtimeCallStackSize; + } + + @Override + public int lookupArrayLength(Constant array) { + if (!array.getKind().isObject() || array.isNull() || !array.asObject().getClass().isArray()) { + throw new IllegalArgumentException(array + " is not an array"); + } + return Array.getLength(array.asObject()); + } + + @Override + public void lower(Node n, LoweringTool tool) { + StructuredGraph graph = (StructuredGraph) n.graph(); + Kind wordKind = graalRuntime.getTarget().wordKind; + if (n instanceof ArrayLengthNode) { + ArrayLengthNode arrayLengthNode = (ArrayLengthNode) n; + SafeReadNode safeReadArrayLength = safeReadArrayLength(arrayLengthNode.array(), StructuredGraph.INVALID_GRAPH_ID); + graph.replaceFixedWithFixed(arrayLengthNode, safeReadArrayLength); + } else if (n instanceof Invoke) { + Invoke invoke = (Invoke) n; + if (invoke.callTarget() instanceof MethodCallTargetNode) { + MethodCallTargetNode callTarget = invoke.methodCallTarget(); + NodeInputList parameters = callTarget.arguments(); + ValueNode receiver = parameters.size() <= 0 ? null : parameters.get(0); + if (!callTarget.isStatic() && receiver.kind() == Kind.Object && !receiver.objectStamp().nonNull()) { + invoke.node().dependencies().add(tool.createNullCheckGuard(receiver, invoke.leafGraphId())); + } + Kind[] signature = MetaUtil.signatureToKinds(callTarget.targetMethod().getSignature(), callTarget.isStatic() ? null : callTarget.targetMethod().getDeclaringClass().getKind()); + + AbstractCallTargetNode loweredCallTarget = null; + if (callTarget.invokeKind() == InvokeKind.Virtual && + GraalOptions.InlineVTableStubs && + (GraalOptions.AlwaysInlineVTableStubs || invoke.isPolymorphic())) { + + HotSpotResolvedJavaMethod hsMethod = (HotSpotResolvedJavaMethod) callTarget.targetMethod(); + if (!hsMethod.getDeclaringClass().isInterface()) { + int vtableEntryOffset = hsMethod.vtableEntryOffset(); + if (vtableEntryOffset > 0) { + // We use LocationNode.ANY_LOCATION for the reads that access the vtable entry and the compiled code entry + // as HotSpot does not guarantee they are final values. + assert vtableEntryOffset > 0; + LoadHubNode hub = graph.add(new LoadHubNode(receiver, wordKind)); + ReadNode metaspaceMethod = graph.add(new ReadNode(hub, LocationNode.create(LocationNode.ANY_LOCATION, wordKind, vtableEntryOffset, graph), StampFactory.forKind(wordKind()))); + ReadNode compiledEntry = graph.add(new ReadNode(metaspaceMethod, LocationNode.create(LocationNode.ANY_LOCATION, wordKind, config.methodCompiledEntryOffset, graph), StampFactory.forKind(wordKind()))); + + loweredCallTarget = graph.add(new HotSpotIndirectCallTargetNode(metaspaceMethod, compiledEntry, parameters, invoke.node().stamp(), signature, callTarget.targetMethod(), CallingConvention.Type.JavaCall)); + + graph.addBeforeFixed(invoke.node(), hub); + graph.addAfterFixed(hub, metaspaceMethod); + graph.addAfterFixed(metaspaceMethod, compiledEntry); + } + } + } + + if (loweredCallTarget == null) { + loweredCallTarget = graph.add(new HotSpotDirectCallTargetNode(parameters, invoke.node().stamp(), signature, callTarget.targetMethod(), CallingConvention.Type.JavaCall, callTarget.invokeKind())); + } + callTarget.replaceAndDelete(loweredCallTarget); + } + } else if (n instanceof LoadFieldNode) { + LoadFieldNode field = (LoadFieldNode) n; + int displacement = ((HotSpotResolvedJavaField) field.field()).offset(); + assert field.kind() != Kind.Illegal; + ReadNode memoryRead = graph.add(new ReadNode(field.object(), LocationNode.create(field.field(), field.field().getKind(), displacement, graph), field.stamp())); + memoryRead.dependencies().add(tool.createNullCheckGuard(field.object(), field.leafGraphId())); + graph.replaceFixedWithFixed(field, memoryRead); + if (field.isVolatile()) { + MembarNode preMembar = graph.add(new MembarNode(JMM_PRE_VOLATILE_READ)); + graph.addBeforeFixed(memoryRead, preMembar); + MembarNode postMembar = graph.add(new MembarNode(JMM_POST_VOLATILE_READ)); + graph.addAfterFixed(memoryRead, postMembar); + } + } else if (n instanceof StoreFieldNode) { + StoreFieldNode storeField = (StoreFieldNode) n; + HotSpotResolvedJavaField field = (HotSpotResolvedJavaField) storeField.field(); + WriteNode memoryWrite = graph.add(new WriteNode(storeField.object(), storeField.value(), LocationNode.create(field, field.getKind(), field.offset(), graph))); + memoryWrite.dependencies().add(tool.createNullCheckGuard(storeField.object(), storeField.leafGraphId())); + memoryWrite.setStateAfter(storeField.stateAfter()); + graph.replaceFixedWithFixed(storeField, memoryWrite); + FixedWithNextNode last = memoryWrite; + if (field.getKind() == Kind.Object && !memoryWrite.value().objectStamp().alwaysNull()) { + FieldWriteBarrier writeBarrier = graph.add(new FieldWriteBarrier(memoryWrite.object())); + graph.addAfterFixed(memoryWrite, writeBarrier); + last = writeBarrier; + } + if (storeField.isVolatile()) { + MembarNode preMembar = graph.add(new MembarNode(JMM_PRE_VOLATILE_WRITE)); + graph.addBeforeFixed(memoryWrite, preMembar); + MembarNode postMembar = graph.add(new MembarNode(JMM_POST_VOLATILE_WRITE)); + graph.addAfterFixed(last, postMembar); + } + } else if (n instanceof CompareAndSwapNode) { + // Separate out GC barrier semantics + CompareAndSwapNode cas = (CompareAndSwapNode) n; + ValueNode expected = cas.expected(); + if (expected.kind() == Kind.Object && !cas.newValue().objectStamp().alwaysNull()) { + ResolvedJavaType type = cas.object().objectStamp().type(); + if (type != null && !type.isArrayClass() && type.toJava() != Object.class) { + // Use a field write barrier since it's not an array store + FieldWriteBarrier writeBarrier = graph.add(new FieldWriteBarrier(cas.object())); + graph.addAfterFixed(cas, writeBarrier); + } else { + // This may be an array store so use an array write barrier + LocationNode location = IndexedLocationNode.create(LocationNode.ANY_LOCATION, cas.expected().kind(), cas.displacement(), cas.offset(), graph, false); + graph.addAfterFixed(cas, graph.add(new ArrayWriteBarrier(cas.object(), location))); + } + } + } else if (n instanceof LoadIndexedNode) { + LoadIndexedNode loadIndexed = (LoadIndexedNode) n; + ValueNode boundsCheck = createBoundsCheck(loadIndexed, tool); + Kind elementKind = loadIndexed.elementKind(); + LocationNode arrayLocation = createArrayLocation(graph, elementKind, loadIndexed.index()); + ReadNode memoryRead = graph.add(new ReadNode(loadIndexed.array(), arrayLocation, loadIndexed.stamp())); + memoryRead.dependencies().add(boundsCheck); + graph.replaceFixedWithFixed(loadIndexed, memoryRead); + } else if (n instanceof StoreIndexedNode) { + StoreIndexedNode storeIndexed = (StoreIndexedNode) n; + ValueNode boundsCheck = createBoundsCheck(storeIndexed, tool); + + Kind elementKind = storeIndexed.elementKind(); + LocationNode arrayLocation = createArrayLocation(graph, elementKind, storeIndexed.index()); + ValueNode value = storeIndexed.value(); + ValueNode array = storeIndexed.array(); + if (elementKind == Kind.Object && !value.objectStamp().alwaysNull()) { + // Store check! + ResolvedJavaType arrayType = array.objectStamp().type(); + if (arrayType != null && array.objectStamp().isExactType()) { + ResolvedJavaType elementType = arrayType.getComponentType(); + if (!MetaUtil.isJavaLangObject(elementType)) { + CheckCastNode checkcast = graph.add(new CheckCastNode(elementType, value, null)); + graph.addBeforeFixed(storeIndexed, checkcast); + value = checkcast; + } + } else { + LoadHubNode arrayClass = graph.add(new LoadHubNode(array, wordKind)); + LocationNode location = LocationNode.create(LocationNode.FINAL_LOCATION, wordKind, config.arrayClassElementOffset, graph); + FloatingReadNode arrayElementKlass = graph.unique(new FloatingReadNode(arrayClass, location, null, StampFactory.forKind(wordKind()))); + CheckCastDynamicNode checkcast = graph.add(new CheckCastDynamicNode(arrayElementKlass, value)); + graph.addBeforeFixed(storeIndexed, checkcast); + graph.addBeforeFixed(checkcast, arrayClass); + value = checkcast; + } + } + WriteNode memoryWrite = graph.add(new WriteNode(array, value, arrayLocation)); + memoryWrite.dependencies().add(boundsCheck); + memoryWrite.setStateAfter(storeIndexed.stateAfter()); + + graph.replaceFixedWithFixed(storeIndexed, memoryWrite); + + if (elementKind == Kind.Object && !value.objectStamp().alwaysNull()) { + graph.addAfterFixed(memoryWrite, graph.add(new ArrayWriteBarrier(array, arrayLocation))); + } + } else if (n instanceof UnsafeLoadNode) { + UnsafeLoadNode load = (UnsafeLoadNode) n; + assert load.kind() != Kind.Illegal; + IndexedLocationNode location = IndexedLocationNode.create(LocationNode.ANY_LOCATION, load.loadKind(), load.displacement(), load.offset(), graph, false); + ReadNode memoryRead = graph.add(new ReadNode(load.object(), location, load.stamp())); + // An unsafe read must not floating outside its block as may float above an explicit null check on its object. + memoryRead.dependencies().add(BeginNode.prevBegin(load)); + graph.replaceFixedWithFixed(load, memoryRead); + } else if (n instanceof UnsafeStoreNode) { + UnsafeStoreNode store = (UnsafeStoreNode) n; + IndexedLocationNode location = IndexedLocationNode.create(LocationNode.ANY_LOCATION, store.storeKind(), store.displacement(), store.offset(), graph, false); + ValueNode object = store.object(); + WriteNode write = graph.add(new WriteNode(object, store.value(), location)); + write.setStateAfter(store.stateAfter()); + graph.replaceFixedWithFixed(store, write); + if (write.value().kind() == Kind.Object && !write.value().objectStamp().alwaysNull()) { + ResolvedJavaType type = object.objectStamp().type(); + WriteBarrier writeBarrier; + if (type != null && !type.isArrayClass() && type.toJava() != Object.class) { + // Use a field write barrier since it's not an array store + writeBarrier = graph.add(new FieldWriteBarrier(object)); + } else { + // This may be an array store so use an array write barrier + writeBarrier = graph.add(new ArrayWriteBarrier(object, location)); + } + graph.addAfterFixed(write, writeBarrier); + } + } else if (n instanceof LoadHubNode) { + LoadHubNode loadHub = (LoadHubNode) n; + assert loadHub.kind() == wordKind; + LocationNode location = LocationNode.create(LocationNode.FINAL_LOCATION, wordKind, config.hubOffset, graph); + ValueNode object = loadHub.object(); + assert !object.isConstant(); + ValueNode guard = tool.createNullCheckGuard(object, StructuredGraph.INVALID_GRAPH_ID); + ReadNode hub = graph.add(new ReadNode(object, location, StampFactory.forKind(wordKind()))); + hub.dependencies().add(guard); + graph.replaceFixed(loadHub, hub); + } else if (n instanceof CheckCastNode) { + checkcastSnippets.lower((CheckCastNode) n, tool); + } else if (n instanceof CheckCastDynamicNode) { + checkcastSnippets.lower((CheckCastDynamicNode) n); + } else if (n instanceof InstanceOfNode) { + instanceofSnippets.lower((InstanceOfNode) n, tool); + } else if (n instanceof NewInstanceNode) { + newObjectSnippets.lower((NewInstanceNode) n, tool); + } else if (n instanceof NewArrayNode) { + newObjectSnippets.lower((NewArrayNode) n, tool); + } else if (n instanceof MonitorEnterNode) { + monitorSnippets.lower((MonitorEnterNode) n, tool); + } else if (n instanceof MonitorExitNode) { + monitorSnippets.lower((MonitorExitNode) n, tool); + } else if (n instanceof TLABAllocateNode) { + newObjectSnippets.lower((TLABAllocateNode) n, tool); + } else if (n instanceof InitializeObjectNode) { + newObjectSnippets.lower((InitializeObjectNode) n, tool); + } else if (n instanceof InitializeArrayNode) { + newObjectSnippets.lower((InitializeArrayNode) n, tool); + } else if (n instanceof NewMultiArrayNode) { + newObjectSnippets.lower((NewMultiArrayNode) n, tool); + } else { + assert false : "Node implementing Lowerable not handled: " + n; + throw GraalInternalError.shouldNotReachHere(); + } + } + + private static IndexedLocationNode createArrayLocation(Graph graph, Kind elementKind, ValueNode index) { + return IndexedLocationNode.create(LocationNode.getArrayLocation(elementKind), elementKind, elementKind.getArrayBaseOffset(), index, graph, true); + } + + private SafeReadNode safeReadArrayLength(ValueNode array, long leafGraphId) { + return safeRead(array.graph(), Kind.Int, array, config.arrayLengthOffset, StampFactory.positiveInt(), leafGraphId); + } + + private static ValueNode createBoundsCheck(AccessIndexedNode n, LoweringTool tool) { + StructuredGraph graph = (StructuredGraph) n.graph(); + ArrayLengthNode arrayLength = graph.add(new ArrayLengthNode(n.array())); + ValueNode guard = tool.createGuard(graph.unique(new IntegerBelowThanNode(n.index(), arrayLength)), BoundsCheckException, InvalidateReprofile, n.leafGraphId()); + + graph.addBeforeFixed(n, arrayLength); + return guard; + } + + @Override + public StructuredGraph intrinsicGraph(ResolvedJavaMethod caller, int bci, ResolvedJavaMethod method, List parameters) { + ResolvedJavaType holder = method.getDeclaringClass(); + String fullName = method.getName() + ((HotSpotSignature) method.getSignature()).asString(); + Kind wordKind = graalRuntime.getTarget().wordKind; + if (holder.toJava() == Object.class) { + if (fullName.equals("getClass()Ljava/lang/Class;")) { + ValueNode obj = (ValueNode) parameters.get(0); + ObjectStamp stamp = (ObjectStamp) obj.stamp(); + if (stamp.nonNull() && stamp.isExactType()) { + StructuredGraph graph = new StructuredGraph(); + ValueNode result = ConstantNode.forObject(stamp.type().toJava(), this, graph); + ReturnNode ret = graph.add(new ReturnNode(result)); + graph.start().setNext(ret); + return graph; + } + StructuredGraph graph = new StructuredGraph(); + LocalNode receiver = graph.unique(new LocalNode(0, StampFactory.objectNonNull())); + LoadHubNode hub = graph.add(new LoadHubNode(receiver, wordKind)); + Stamp resultStamp = StampFactory.declaredNonNull(lookupJavaType(Class.class)); + FloatingReadNode result = graph.unique(new FloatingReadNode(hub, LocationNode.create(LocationNode.FINAL_LOCATION, Kind.Object, config.classMirrorOffset, graph), null, resultStamp)); + ReturnNode ret = graph.add(new ReturnNode(result)); + graph.start().setNext(hub); + hub.setNext(ret); + return graph; + } + } else if (holder.toJava() == Class.class) { + if (fullName.equals("getModifiers()I")) { + StructuredGraph graph = new StructuredGraph(); + LocalNode receiver = graph.unique(new LocalNode(0, StampFactory.objectNonNull())); + SafeReadNode klass = safeRead(graph, wordKind, receiver, config.klassOffset, StampFactory.forKind(wordKind), INVALID_GRAPH_ID); + graph.start().setNext(klass); + LocationNode location = LocationNode.create(LocationNode.FINAL_LOCATION, Kind.Int, config.klassModifierFlagsOffset, graph); + FloatingReadNode readModifiers = graph.unique(new FloatingReadNode(klass, location, null, StampFactory.intValue())); + CompareNode isZero = CompareNode.createCompareNode(Condition.EQ, klass, ConstantNode.defaultForKind(wordKind, graph)); + GuardNode guard = graph.unique(new GuardNode(isZero, graph.start(), NullCheckException, InvalidateReprofile, true, INVALID_GRAPH_ID)); + readModifiers.dependencies().add(guard); + ReturnNode ret = graph.add(new ReturnNode(readModifiers)); + klass.setNext(ret); + return graph; + } + } else if (holder.toJava() == Thread.class) { + if (fullName.equals("currentThread()Ljava/lang/Thread;")) { + StructuredGraph graph = new StructuredGraph(); + ReturnNode ret = graph.add(new ReturnNode(graph.unique(new CurrentThread(config.threadObjectOffset, this)))); + graph.start().setNext(ret); + return graph; + } + } + return null; + } + + private static SafeReadNode safeRead(Graph graph, Kind kind, ValueNode value, int offset, Stamp stamp, long leafGraphId) { + return graph.add(new SafeReadNode(value, LocationNode.create(LocationNode.FINAL_LOCATION, kind, offset, graph), stamp, leafGraphId)); + } + + public ResolvedJavaType lookupJavaType(Class clazz) { + return HotSpotResolvedJavaType.fromClass(clazz); + } + + public Object lookupCallTarget(Object target) { + if (target instanceof HotSpotRuntimeCall) { + return ((HotSpotRuntimeCall) target).address; + } + return target; + } + + public RuntimeCall lookupRuntimeCall(Descriptor descriptor) { + assert runtimeCalls.containsKey(descriptor) : descriptor; + return runtimeCalls.get(descriptor); + } + + public ResolvedJavaMethod lookupJavaMethod(Method reflectionMethod) { + CompilerToVM c2vm = graalRuntime.getCompilerToVM(); + HotSpotResolvedJavaType[] resultHolder = {null}; + long metaspaceMethod = c2vm.getMetaspaceMethod(reflectionMethod, resultHolder); + assert metaspaceMethod != 0L; + return resultHolder[0].createMethod(metaspaceMethod); + } + + @Override + public ResolvedJavaField lookupJavaField(Field reflectionField) { + return graalRuntime.getCompilerToVM().getJavaField(reflectionField); + } + + private static HotSpotCodeInfo makeInfo(ResolvedJavaMethod method, CompilationResult compResult, CodeInfo[] info) { + HotSpotCodeInfo hsInfo = null; + if (info != null && info.length > 0) { + hsInfo = new HotSpotCodeInfo(compResult, (HotSpotResolvedJavaMethod) method); + info[0] = hsInfo; + } + return hsInfo; + } + + public void installMethod(HotSpotResolvedJavaMethod method, int entryBCI, CompilationResult compResult, CodeInfo[] info) { + HotSpotCodeInfo hsInfo = makeInfo(method, compResult, info); + graalRuntime.getCompilerToVM().installCode(new HotSpotCompilationResult(method, entryBCI, compResult), null, hsInfo); + } + + @Override + public InstalledCode addMethod(ResolvedJavaMethod method, CompilationResult compResult, CodeInfo[] info) { + HotSpotCodeInfo hsInfo = makeInfo(method, compResult, info); + HotSpotResolvedJavaMethod hotspotMethod = (HotSpotResolvedJavaMethod) method; + return graalRuntime.getCompilerToVM().installCode(new HotSpotCompilationResult(hotspotMethod, -1, compResult), new HotSpotInstalledCode(hotspotMethod), hsInfo); + } + + @Override + public int encodeDeoptActionAndReason(DeoptimizationAction action, DeoptimizationReason reason) { + final int actionShift = 0; + final int reasonShift = 3; + + int actionValue = convertDeoptAction(action); + int reasonValue = convertDeoptReason(reason); + return (~(((reasonValue) << reasonShift) + ((actionValue) << actionShift))); + } + + public int convertDeoptAction(DeoptimizationAction action) { + // This must be kept in sync with the DeoptAction enum defined in deoptimization.hpp + switch(action) { + case None: return 0; + case RecompileIfTooManyDeopts: return 1; + case InvalidateReprofile: return 2; + case InvalidateRecompile: return 3; + case InvalidateStopCompiling: return 4; + default: throw GraalInternalError.shouldNotReachHere(); + } + } + + public int convertDeoptReason(DeoptimizationReason reason) { + // This must be kept in sync with the DeoptReason enum defined in deoptimization.hpp + switch(reason) { + case None: return 0; + case NullCheckException: return 1; + case BoundsCheckException: return 2; + case ClassCastException: return 3; + case ArrayStoreException: return 4; + case UnreachedCode: return 5; + case TypeCheckedInliningViolated: return 6; + case OptimizedTypeCheckViolated: return 7; + case NotCompiledExceptionHandler: return 8; + case Unresolved: return 9; + case JavaSubroutineMismatch: return 10; + case ArithmeticException: return 11; + case RuntimeConstraint: return 12; + default: throw GraalInternalError.shouldNotReachHere(); + } + } + + public boolean needsDataPatch(Constant constant) { + return constant.getPrimitiveAnnotation() instanceof HotSpotResolvedJavaType; + } +} diff -r cd2c08049dd5 -r 32408bd16b91 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/NewObjectSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/NewObjectSnippets.java Tue Nov 27 12:12:02 2012 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/NewObjectSnippets.java Tue Nov 27 12:15:18 2012 +0100 @@ -1,404 +1,404 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 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.hotspot.snippets; - -import static com.oracle.graal.api.code.UnsignedMath.*; -import static com.oracle.graal.hotspot.snippets.HotSpotSnippetUtils.*; -import static com.oracle.graal.nodes.extended.UnsafeArrayCastNode.*; -import static com.oracle.graal.nodes.extended.UnsafeCastNode.*; -import static com.oracle.graal.snippets.Snippet.Varargs.*; -import static com.oracle.graal.snippets.SnippetTemplate.*; -import static com.oracle.graal.snippets.SnippetTemplate.Arguments.*; -import static com.oracle.graal.snippets.nodes.DirectObjectStoreNode.*; -import static com.oracle.graal.snippets.nodes.ExplodeLoopNode.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.hotspot.meta.*; -import com.oracle.graal.hotspot.nodes.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.java.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.type.*; -import com.oracle.graal.phases.*; -import com.oracle.graal.snippets.*; -import com.oracle.graal.snippets.Snippet.ConstantParameter; -import com.oracle.graal.snippets.Snippet.Parameter; -import com.oracle.graal.snippets.Snippet.VarargsParameter; -import com.oracle.graal.snippets.SnippetTemplate.AbstractTemplates; -import com.oracle.graal.snippets.SnippetTemplate.Arguments; -import com.oracle.graal.snippets.SnippetTemplate.Key; -import com.oracle.graal.snippets.nodes.*; - -/** - * Snippets used for implementing NEW, ANEWARRAY and NEWARRAY. - */ -public class NewObjectSnippets implements SnippetsInterface { - - @Snippet - public static Word allocate(@Parameter("size") int size) { - Word thread = thread(); - Word top = loadWordFromWord(thread, threadTlabTopOffset()); - Word end = loadWordFromWord(thread, threadTlabEndOffset()); - Word available = end.minus(top); - if (available.aboveOrEqual(Word.fromInt(size))) { - Word newTop = top.plus(size); - storeObject(thread, 0, threadTlabTopOffset(), newTop); - return top; - } - return Word.zero(); - } - - @Snippet - public static Object initializeObject( - @Parameter("memory") Word memory, - @Parameter("hub") Word hub, - @Parameter("prototypeMarkWord") Word prototypeMarkWord, - @ConstantParameter("size") int size, - @ConstantParameter("fillContents") boolean fillContents, - @ConstantParameter("locked") boolean locked) { - - Object result; - if (memory == Word.zero()) { - new_stub.inc(); - result = NewInstanceStubCall.call(hub); - } else { - if (locked) { - formatObject(hub, size, memory, thread().or(biasedLockPattern()), fillContents); - } else { - formatObject(hub, size, memory, prototypeMarkWord, fillContents); - } - result = memory.toObject(); - } - return unsafeCast(verifyOop(result), StampFactory.forNodeIntrinsic()); - } - - @Snippet - public static Object initializeObjectArray( - @Parameter("memory") Word memory, - @Parameter("hub") Word hub, - @Parameter("length") int length, - @Parameter("size") int size, - @Parameter("prototypeMarkWord") Word prototypeMarkWord, - @ConstantParameter("headerSize") int headerSize, - @ConstantParameter("fillContents") boolean fillContents, - @ConstantParameter("locked") boolean locked) { - if (locked) { - return initializeArray(memory, hub, length, size, thread().or(biasedLockPattern()), headerSize, true, fillContents); - } else { - return initializeArray(memory, hub, length, size, prototypeMarkWord, headerSize, true, fillContents); - } - } - - @Snippet - public static Object initializePrimitiveArray( - @Parameter("memory") Word memory, - @Parameter("hub") Word hub, - @Parameter("length") int length, - @Parameter("size") int size, - @Parameter("prototypeMarkWord") Word prototypeMarkWord, - @ConstantParameter("headerSize") int headerSize, - @ConstantParameter("fillContents") boolean fillContents, - @ConstantParameter("locked") boolean locked) { - if (locked) { - return initializeArray(memory, hub, length, size, thread().or(biasedLockPattern()), headerSize, false, fillContents); - } else { - return initializeArray(memory, hub, length, size, prototypeMarkWord, headerSize, false, fillContents); - } - } - - private static Object initializeArray(Word memory, Word hub, int length, int size, Word prototypeMarkWord, int headerSize, boolean isObjectArray, boolean fillContents) { - Object result; - if (memory == Word.zero()) { - if (isObjectArray) { - anewarray_stub.inc(); - } else { - newarray_stub.inc(); - } - result = NewArrayStubCall.call(isObjectArray, hub, length); - } else { - if (isObjectArray) { - anewarray_loopInit.inc(); - } else { - newarray_loopInit.inc(); - } - formatArray(hub, size, length, headerSize, memory, prototypeMarkWord, fillContents); - result = memory.toObject(); - } - return unsafeArrayCast(verifyOop(result), length, StampFactory.forNodeIntrinsic()); - } - - /** - * Maximum array length for which fast path allocation is used. - */ - private static final int MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH = 0x00FFFFFF; - - @Snippet - public static Object allocateArrayAndInitialize( - @Parameter("length") int length, - @ConstantParameter("alignment") int alignment, - @ConstantParameter("headerSize") int headerSize, - @ConstantParameter("log2ElementSize") int log2ElementSize, - @ConstantParameter("type") ResolvedJavaType type) { - if (!belowThan(length, MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH)) { - // This handles both negative array sizes and very large array sizes - DeoptimizeNode.deopt(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.RuntimeConstraint); - } - int size = getArraySize(length, alignment, headerSize, log2ElementSize); - Word memory = TLABAllocateNode.allocateVariableSize(size); - return InitializeArrayNode.initialize(memory, length, size, type, true, false); - } - - public static int getArraySize(int length, int alignment, int headerSize, int log2ElementSize) { - int size = (length << log2ElementSize) + headerSize + (alignment - 1); - int mask = ~(alignment - 1); - return size & mask; - } - - /** - * Calls the runtime stub for implementing MULTIANEWARRAY. - */ - @Snippet - public static Object newmultiarray( - @Parameter("hub") Word hub, - @ConstantParameter("rank") int rank, - @VarargsParameter("dimensions") int[] dimensions) { - Word dims = DimensionsNode.allocaDimsArray(rank); - ExplodeLoopNode.explodeLoop(); - for (int i = 0; i < rank; i++) { - DirectObjectStoreNode.storeInt(dims, 0, i * 4, dimensions[i]); - } - return NewMultiArrayStubCall.call(hub, rank, dims); - } - - /** - * Maximum size of an object whose body is initialized by a sequence of - * zero-stores to its fields. Larger objects have their bodies initialized - * in a loop. - */ - private static final int MAX_UNROLLED_OBJECT_ZEROING_SIZE = 10 * wordSize(); - - /** - * Formats some allocated memory with an object header zeroes out the rest. - */ - private static void formatObject(Word hub, int size, Word memory, Word compileTimePrototypeMarkWord, boolean fillContents) { - Word prototypeMarkWord = useBiasedLocking() ? loadWordFromWord(hub, prototypeMarkWordOffset()) : compileTimePrototypeMarkWord; - storeWord(memory, 0, markOffset(), prototypeMarkWord); - storeWord(memory, 0, hubOffset(), hub); - if (fillContents) { - if (size <= MAX_UNROLLED_OBJECT_ZEROING_SIZE) { - new_seqInit.inc(); - explodeLoop(); - for (int offset = 2 * wordSize(); offset < size; offset += wordSize()) { - storeWord(memory, 0, offset, Word.zero()); - } - } else { - new_loopInit.inc(); - for (int offset = 2 * wordSize(); offset < size; offset += wordSize()) { - storeWord(memory, 0, offset, Word.zero()); - } - } - } - } - - /** - * Formats some allocated memory with an object header zeroes out the rest. - */ - private static void formatArray(Word hub, int size, int length, int headerSize, Word memory, Word prototypeMarkWord, boolean fillContents) { - storeWord(memory, 0, markOffset(), prototypeMarkWord); - storeWord(memory, 0, hubOffset(), hub); - storeInt(memory, 0, arrayLengthOffset(), length); - if (fillContents) { - for (int offset = headerSize; offset < size; offset += wordSize()) { - storeWord(memory, 0, offset, Word.zero()); - } - } - } - - public static class Templates extends AbstractTemplates { - - private final ResolvedJavaMethod allocate; - private final ResolvedJavaMethod initializeObject; - private final ResolvedJavaMethod initializeObjectArray; - private final ResolvedJavaMethod initializePrimitiveArray; - private final ResolvedJavaMethod allocateArrayAndInitialize; - private final ResolvedJavaMethod newmultiarray; - private final TargetDescription target; - private final boolean useTLAB; - - public Templates(CodeCacheProvider runtime, Assumptions assumptions, TargetDescription target, boolean useTLAB) { - super(runtime, assumptions, target, NewObjectSnippets.class); - this.target = target; - this.useTLAB = useTLAB; - allocate = snippet("allocate", int.class); - initializeObject = snippet("initializeObject", Word.class, Word.class, Word.class, int.class, boolean.class, boolean.class); - initializeObjectArray = snippet("initializeObjectArray", Word.class, Word.class, int.class, int.class, Word.class, int.class, boolean.class, boolean.class); - initializePrimitiveArray = snippet("initializePrimitiveArray", Word.class, Word.class, int.class, int.class, Word.class, int.class, boolean.class, boolean.class); - allocateArrayAndInitialize = snippet("allocateArrayAndInitialize", int.class, int.class, int.class, int.class, ResolvedJavaType.class); - newmultiarray = snippet("newmultiarray", Word.class, int.class, int[].class); - } - - /** - * Lowers a {@link NewInstanceNode}. - */ - @SuppressWarnings("unused") - public void lower(NewInstanceNode newInstanceNode, LoweringTool tool) { - StructuredGraph graph = (StructuredGraph) newInstanceNode.graph(); - HotSpotResolvedJavaType type = (HotSpotResolvedJavaType) newInstanceNode.instanceClass(); - ConstantNode hub = ConstantNode.forConstant(type.klass(), runtime, graph); - int size = type.instanceSize(); - assert (size % wordSize()) == 0; - assert size >= 0; - - ValueNode memory; - if (!useTLAB) { - memory = ConstantNode.forConstant(new Constant(target.wordKind, 0L), runtime, graph); - } else { - ConstantNode sizeNode = ConstantNode.forInt(size, graph); - TLABAllocateNode tlabAllocateNode = graph.add(new TLABAllocateNode(sizeNode)); - graph.addBeforeFixed(newInstanceNode, tlabAllocateNode); - memory = tlabAllocateNode; - } - InitializeObjectNode initializeNode = graph.add(new InitializeObjectNode(memory, type, newInstanceNode.fillContents(), newInstanceNode.locked())); - graph.replaceFixedWithFixed(newInstanceNode, initializeNode); - } - - /** - * Lowers a {@link NewArrayNode}. - */ - @SuppressWarnings("unused") - public void lower(NewArrayNode newArrayNode, LoweringTool tool) { - StructuredGraph graph = (StructuredGraph) newArrayNode.graph(); - ValueNode lengthNode = newArrayNode.length(); - TLABAllocateNode tlabAllocateNode; - ResolvedJavaType elementType = newArrayNode.elementType(); - ResolvedJavaType arrayType = elementType.getArrayClass(); - Kind elementKind = elementType.getKind(); - final int alignment = target.wordSize; - final int headerSize = elementKind.getArrayBaseOffset(); - final Integer length = lengthNode.isConstant() ? Integer.valueOf(lengthNode.asConstant().asInt()) : null; - int log2ElementSize = CodeUtil.log2(target.sizeInBytes(elementKind)); - if (!useTLAB) { - ConstantNode zero = ConstantNode.forConstant(new Constant(target.wordKind, 0L), runtime, graph); - // value for 'size' doesn't matter as it isn't used since a stub call will be made anyway - // for both allocation and initialization - it just needs to be non-null - ConstantNode size = ConstantNode.forInt(-1, graph); - InitializeArrayNode initializeNode = graph.add(new InitializeArrayNode(zero, lengthNode, size, arrayType, newArrayNode.fillContents(), newArrayNode.locked())); - graph.replaceFixedWithFixed(newArrayNode, initializeNode); - } else if (length != null && belowThan(length, MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH)) { - // Calculate aligned size - int size = getArraySize(length, alignment, headerSize, log2ElementSize); - ConstantNode sizeNode = ConstantNode.forInt(size, graph); - tlabAllocateNode = graph.add(new TLABAllocateNode(sizeNode)); - graph.addBeforeFixed(newArrayNode, tlabAllocateNode); - InitializeArrayNode initializeNode = graph.add(new InitializeArrayNode(tlabAllocateNode, lengthNode, sizeNode, arrayType, newArrayNode.fillContents(), newArrayNode.locked())); - graph.replaceFixedWithFixed(newArrayNode, initializeNode); - } else { - Key key = new Key(allocateArrayAndInitialize). - add("alignment", alignment). - add("headerSize", headerSize). - add("log2ElementSize", log2ElementSize). - add("type", arrayType); - Arguments arguments = new Arguments().add("length", lengthNode); - SnippetTemplate template = cache.get(key, assumptions); - Debug.log("Lowering allocateArrayAndInitialize in %s: node=%s, template=%s, arguments=%s", graph, newArrayNode, template, arguments); - template.instantiate(runtime, newArrayNode, DEFAULT_REPLACER, arguments); - } - } - - @SuppressWarnings("unused") - public void lower(TLABAllocateNode tlabAllocateNode, LoweringTool tool) { - StructuredGraph graph = (StructuredGraph) tlabAllocateNode.graph(); - ValueNode size = tlabAllocateNode.size(); - Key key = new Key(allocate); - Arguments arguments = arguments("size", size); - SnippetTemplate template = cache.get(key, assumptions); - Debug.log("Lowering fastAllocate in %s: node=%s, template=%s, arguments=%s", graph, tlabAllocateNode, template, arguments); - template.instantiate(runtime, tlabAllocateNode, DEFAULT_REPLACER, arguments); - } - - @SuppressWarnings("unused") - public void lower(InitializeObjectNode initializeNode, LoweringTool tool) { - StructuredGraph graph = (StructuredGraph) initializeNode.graph(); - HotSpotResolvedJavaType type = (HotSpotResolvedJavaType) initializeNode.type(); - assert !type.isArrayClass(); - ConstantNode hub = ConstantNode.forConstant(type.klass(), runtime, graph); - int size = type.instanceSize(); - assert (size % wordSize()) == 0; - assert size >= 0; - Key key = new Key(initializeObject).add("size", size).add("fillContents", initializeNode.fillContents()).add("locked", initializeNode.locked()); - ValueNode memory = initializeNode.memory(); - Arguments arguments = arguments("memory", memory).add("hub", hub).add("prototypeMarkWord", type.prototypeMarkWord()); - SnippetTemplate template = cache.get(key, assumptions); - Debug.log("Lowering initializeObject in %s: node=%s, template=%s, arguments=%s", graph, initializeNode, template, arguments); - template.instantiate(runtime, initializeNode, DEFAULT_REPLACER, arguments); - } - - @SuppressWarnings("unused") - public void lower(InitializeArrayNode initializeNode, LoweringTool tool) { - StructuredGraph graph = (StructuredGraph) initializeNode.graph(); - HotSpotResolvedJavaType type = (HotSpotResolvedJavaType) initializeNode.type(); - ResolvedJavaType elementType = type.getComponentType(); - assert elementType != null; - ConstantNode hub = ConstantNode.forConstant(type.klass(), runtime, graph); - Kind elementKind = elementType.getKind(); - final int headerSize = elementKind.getArrayBaseOffset(); - Key key = new Key(elementKind.isObject() ? initializeObjectArray : initializePrimitiveArray).add("headerSize", headerSize).add("fillContents", initializeNode.fillContents()).add("locked", initializeNode.locked()); - ValueNode memory = initializeNode.memory(); - Arguments arguments = arguments("memory", memory).add("hub", hub).add("prototypeMarkWord", type.prototypeMarkWord()).add("size", initializeNode.size()).add("length", initializeNode.length()); - SnippetTemplate template = cache.get(key, assumptions); - Debug.log("Lowering initializeObjectArray in %s: node=%s, template=%s, arguments=%s", graph, initializeNode, template, arguments); - template.instantiate(runtime, initializeNode, DEFAULT_REPLACER, arguments); - } - - @SuppressWarnings("unused") - public void lower(NewMultiArrayNode newmultiarrayNode, LoweringTool tool) { - StructuredGraph graph = (StructuredGraph) newmultiarrayNode.graph(); - int rank = newmultiarrayNode.dimensionCount(); - ValueNode[] dims = new ValueNode[rank]; - for (int i = 0; i < newmultiarrayNode.dimensionCount(); i++) { - dims[i] = newmultiarrayNode.dimension(i); - } - HotSpotResolvedJavaType type = (HotSpotResolvedJavaType) newmultiarrayNode.type(); - ConstantNode hub = ConstantNode.forConstant(type.klass(), runtime, graph); - Key key = new Key(newmultiarray).add("dimensions", vargargs(new int[rank], StampFactory.forKind(Kind.Int))).add("rank", rank); - Arguments arguments = arguments("dimensions", dims).add("hub", hub); - SnippetTemplate template = cache.get(key, assumptions); - template.instantiate(runtime, newmultiarrayNode, DEFAULT_REPLACER, arguments); - } - } - - private static final SnippetCounter.Group countersNew = GraalOptions.SnippetCounters ? new SnippetCounter.Group("NewInstance") : null; - private static final SnippetCounter new_seqInit = new SnippetCounter(countersNew, "tlabSeqInit", "TLAB alloc with unrolled zeroing"); - private static final SnippetCounter new_loopInit = new SnippetCounter(countersNew, "tlabLoopInit", "TLAB alloc with zeroing in a loop"); - private static final SnippetCounter new_stub = new SnippetCounter(countersNew, "stub", "alloc and zeroing via stub"); - - private static final SnippetCounter.Group countersNewPrimitiveArray = GraalOptions.SnippetCounters ? new SnippetCounter.Group("NewPrimitiveArray") : null; - private static final SnippetCounter newarray_loopInit = new SnippetCounter(countersNewPrimitiveArray, "tlabLoopInit", "TLAB alloc with zeroing in a loop"); - private static final SnippetCounter newarray_stub = new SnippetCounter(countersNewPrimitiveArray, "stub", "alloc and zeroing via stub"); - - private static final SnippetCounter.Group countersNewObjectArray = GraalOptions.SnippetCounters ? new SnippetCounter.Group("NewObjectArray") : null; - private static final SnippetCounter anewarray_loopInit = new SnippetCounter(countersNewObjectArray, "tlabLoopInit", "TLAB alloc with zeroing in a loop"); - private static final SnippetCounter anewarray_stub = new SnippetCounter(countersNewObjectArray, "stub", "alloc and zeroing via stub"); -} +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 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.hotspot.snippets; + +import static com.oracle.graal.api.code.UnsignedMath.*; +import static com.oracle.graal.hotspot.snippets.HotSpotSnippetUtils.*; +import static com.oracle.graal.nodes.extended.UnsafeArrayCastNode.*; +import static com.oracle.graal.nodes.extended.UnsafeCastNode.*; +import static com.oracle.graal.snippets.Snippet.Varargs.*; +import static com.oracle.graal.snippets.SnippetTemplate.*; +import static com.oracle.graal.snippets.SnippetTemplate.Arguments.*; +import static com.oracle.graal.snippets.nodes.DirectObjectStoreNode.*; +import static com.oracle.graal.snippets.nodes.ExplodeLoopNode.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.hotspot.nodes.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; +import com.oracle.graal.phases.*; +import com.oracle.graal.snippets.*; +import com.oracle.graal.snippets.Snippet.ConstantParameter; +import com.oracle.graal.snippets.Snippet.Parameter; +import com.oracle.graal.snippets.Snippet.VarargsParameter; +import com.oracle.graal.snippets.SnippetTemplate.AbstractTemplates; +import com.oracle.graal.snippets.SnippetTemplate.Arguments; +import com.oracle.graal.snippets.SnippetTemplate.Key; +import com.oracle.graal.snippets.nodes.*; + +/** + * Snippets used for implementing NEW, ANEWARRAY and NEWARRAY. + */ +public class NewObjectSnippets implements SnippetsInterface { + + @Snippet + public static Word allocate(@Parameter("size") int size) { + Word thread = thread(); + Word top = loadWordFromWord(thread, threadTlabTopOffset()); + Word end = loadWordFromWord(thread, threadTlabEndOffset()); + Word available = end.minus(top); + if (available.aboveOrEqual(Word.fromInt(size))) { + Word newTop = top.plus(size); + storeObject(thread, 0, threadTlabTopOffset(), newTop); + return top; + } + return Word.zero(); + } + + @Snippet + public static Object initializeObject( + @Parameter("memory") Word memory, + @Parameter("hub") Word hub, + @Parameter("prototypeMarkWord") Word prototypeMarkWord, + @ConstantParameter("size") int size, + @ConstantParameter("fillContents") boolean fillContents, + @ConstantParameter("locked") boolean locked) { + + Object result; + if (memory == Word.zero()) { + new_stub.inc(); + result = NewInstanceStubCall.call(hub); + } else { + if (locked) { + formatObject(hub, size, memory, thread().or(biasedLockPattern()), fillContents); + } else { + formatObject(hub, size, memory, prototypeMarkWord, fillContents); + } + result = memory.toObject(); + } + return unsafeCast(verifyOop(result), StampFactory.forNodeIntrinsic()); + } + + @Snippet + public static Object initializeObjectArray( + @Parameter("memory") Word memory, + @Parameter("hub") Word hub, + @Parameter("length") int length, + @Parameter("size") int size, + @Parameter("prototypeMarkWord") Word prototypeMarkWord, + @ConstantParameter("headerSize") int headerSize, + @ConstantParameter("fillContents") boolean fillContents, + @ConstantParameter("locked") boolean locked) { + if (locked) { + return initializeArray(memory, hub, length, size, thread().or(biasedLockPattern()), headerSize, true, fillContents); + } else { + return initializeArray(memory, hub, length, size, prototypeMarkWord, headerSize, true, fillContents); + } + } + + @Snippet + public static Object initializePrimitiveArray( + @Parameter("memory") Word memory, + @Parameter("hub") Word hub, + @Parameter("length") int length, + @Parameter("size") int size, + @Parameter("prototypeMarkWord") Word prototypeMarkWord, + @ConstantParameter("headerSize") int headerSize, + @ConstantParameter("fillContents") boolean fillContents, + @ConstantParameter("locked") boolean locked) { + if (locked) { + return initializeArray(memory, hub, length, size, thread().or(biasedLockPattern()), headerSize, false, fillContents); + } else { + return initializeArray(memory, hub, length, size, prototypeMarkWord, headerSize, false, fillContents); + } + } + + private static Object initializeArray(Word memory, Word hub, int length, int size, Word prototypeMarkWord, int headerSize, boolean isObjectArray, boolean fillContents) { + Object result; + if (memory == Word.zero()) { + if (isObjectArray) { + anewarray_stub.inc(); + } else { + newarray_stub.inc(); + } + result = NewArrayStubCall.call(isObjectArray, hub, length); + } else { + if (isObjectArray) { + anewarray_loopInit.inc(); + } else { + newarray_loopInit.inc(); + } + formatArray(hub, size, length, headerSize, memory, prototypeMarkWord, fillContents); + result = memory.toObject(); + } + return unsafeArrayCast(verifyOop(result), length, StampFactory.forNodeIntrinsic()); + } + + /** + * Maximum array length for which fast path allocation is used. + */ + private static final int MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH = 0x00FFFFFF; + + @Snippet + public static Object allocateArrayAndInitialize( + @Parameter("length") int length, + @ConstantParameter("alignment") int alignment, + @ConstantParameter("headerSize") int headerSize, + @ConstantParameter("log2ElementSize") int log2ElementSize, + @ConstantParameter("type") ResolvedJavaType type) { + if (!belowThan(length, MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH)) { + // This handles both negative array sizes and very large array sizes + DeoptimizeNode.deopt(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.RuntimeConstraint); + } + int size = getArraySize(length, alignment, headerSize, log2ElementSize); + Word memory = TLABAllocateNode.allocateVariableSize(size); + return InitializeArrayNode.initialize(memory, length, size, type, true, false); + } + + public static int getArraySize(int length, int alignment, int headerSize, int log2ElementSize) { + int size = (length << log2ElementSize) + headerSize + (alignment - 1); + int mask = ~(alignment - 1); + return size & mask; + } + + /** + * Calls the runtime stub for implementing MULTIANEWARRAY. + */ + @Snippet + public static Object newmultiarray( + @Parameter("hub") Word hub, + @ConstantParameter("rank") int rank, + @VarargsParameter("dimensions") int[] dimensions) { + Word dims = DimensionsNode.allocaDimsArray(rank); + ExplodeLoopNode.explodeLoop(); + for (int i = 0; i < rank; i++) { + DirectObjectStoreNode.storeInt(dims, 0, i * 4, dimensions[i]); + } + return NewMultiArrayStubCall.call(hub, rank, dims); + } + + /** + * Maximum size of an object whose body is initialized by a sequence of + * zero-stores to its fields. Larger objects have their bodies initialized + * in a loop. + */ + private static final int MAX_UNROLLED_OBJECT_ZEROING_SIZE = 10 * wordSize(); + + /** + * Formats some allocated memory with an object header zeroes out the rest. + */ + private static void formatObject(Word hub, int size, Word memory, Word compileTimePrototypeMarkWord, boolean fillContents) { + Word prototypeMarkWord = useBiasedLocking() ? loadWordFromWord(hub, prototypeMarkWordOffset()) : compileTimePrototypeMarkWord; + storeWord(memory, 0, markOffset(), prototypeMarkWord); + storeWord(memory, 0, hubOffset(), hub); + if (fillContents) { + if (size <= MAX_UNROLLED_OBJECT_ZEROING_SIZE) { + new_seqInit.inc(); + explodeLoop(); + for (int offset = 2 * wordSize(); offset < size; offset += wordSize()) { + storeWord(memory, 0, offset, Word.zero()); + } + } else { + new_loopInit.inc(); + for (int offset = 2 * wordSize(); offset < size; offset += wordSize()) { + storeWord(memory, 0, offset, Word.zero()); + } + } + } + } + + /** + * Formats some allocated memory with an object header zeroes out the rest. + */ + private static void formatArray(Word hub, int size, int length, int headerSize, Word memory, Word prototypeMarkWord, boolean fillContents) { + storeWord(memory, 0, markOffset(), prototypeMarkWord); + storeWord(memory, 0, hubOffset(), hub); + storeInt(memory, 0, arrayLengthOffset(), length); + if (fillContents) { + for (int offset = headerSize; offset < size; offset += wordSize()) { + storeWord(memory, 0, offset, Word.zero()); + } + } + } + + public static class Templates extends AbstractTemplates { + + private final ResolvedJavaMethod allocate; + private final ResolvedJavaMethod initializeObject; + private final ResolvedJavaMethod initializeObjectArray; + private final ResolvedJavaMethod initializePrimitiveArray; + private final ResolvedJavaMethod allocateArrayAndInitialize; + private final ResolvedJavaMethod newmultiarray; + private final TargetDescription target; + private final boolean useTLAB; + + public Templates(CodeCacheProvider runtime, Assumptions assumptions, TargetDescription target, boolean useTLAB) { + super(runtime, assumptions, target, NewObjectSnippets.class); + this.target = target; + this.useTLAB = useTLAB; + allocate = snippet("allocate", int.class); + initializeObject = snippet("initializeObject", Word.class, Word.class, Word.class, int.class, boolean.class, boolean.class); + initializeObjectArray = snippet("initializeObjectArray", Word.class, Word.class, int.class, int.class, Word.class, int.class, boolean.class, boolean.class); + initializePrimitiveArray = snippet("initializePrimitiveArray", Word.class, Word.class, int.class, int.class, Word.class, int.class, boolean.class, boolean.class); + allocateArrayAndInitialize = snippet("allocateArrayAndInitialize", int.class, int.class, int.class, int.class, ResolvedJavaType.class); + newmultiarray = snippet("newmultiarray", Word.class, int.class, int[].class); + } + + /** + * Lowers a {@link NewInstanceNode}. + */ + @SuppressWarnings("unused") + public void lower(NewInstanceNode newInstanceNode, LoweringTool tool) { + StructuredGraph graph = (StructuredGraph) newInstanceNode.graph(); + HotSpotResolvedJavaType type = (HotSpotResolvedJavaType) newInstanceNode.instanceClass(); + ConstantNode hub = ConstantNode.forConstant(type.klass(), runtime, graph); + int size = type.instanceSize(); + assert (size % wordSize()) == 0; + assert size >= 0; + + ValueNode memory; + if (!useTLAB) { + memory = ConstantNode.forConstant(new Constant(target.wordKind, 0L), runtime, graph); + } else { + ConstantNode sizeNode = ConstantNode.forInt(size, graph); + TLABAllocateNode tlabAllocateNode = graph.add(new TLABAllocateNode(sizeNode)); + graph.addBeforeFixed(newInstanceNode, tlabAllocateNode); + memory = tlabAllocateNode; + } + InitializeObjectNode initializeNode = graph.add(new InitializeObjectNode(memory, type, newInstanceNode.fillContents(), newInstanceNode.locked())); + graph.replaceFixedWithFixed(newInstanceNode, initializeNode); + } + + /** + * Lowers a {@link NewArrayNode}. + */ + @SuppressWarnings("unused") + public void lower(NewArrayNode newArrayNode, LoweringTool tool) { + StructuredGraph graph = (StructuredGraph) newArrayNode.graph(); + ValueNode lengthNode = newArrayNode.length(); + TLABAllocateNode tlabAllocateNode; + ResolvedJavaType elementType = newArrayNode.elementType(); + ResolvedJavaType arrayType = elementType.getArrayClass(); + Kind elementKind = elementType.getKind(); + final int alignment = target.wordSize; + final int headerSize = elementKind.getArrayBaseOffset(); + final Integer length = lengthNode.isConstant() ? Integer.valueOf(lengthNode.asConstant().asInt()) : null; + int log2ElementSize = CodeUtil.log2(target.sizeInBytes(elementKind)); + if (!useTLAB) { + ConstantNode zero = ConstantNode.forConstant(new Constant(target.wordKind, 0L), runtime, graph); + // value for 'size' doesn't matter as it isn't used since a stub call will be made anyway + // for both allocation and initialization - it just needs to be non-null + ConstantNode size = ConstantNode.forInt(-1, graph); + InitializeArrayNode initializeNode = graph.add(new InitializeArrayNode(zero, lengthNode, size, arrayType, newArrayNode.fillContents(), newArrayNode.locked())); + graph.replaceFixedWithFixed(newArrayNode, initializeNode); + } else if (length != null && belowThan(length, MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH)) { + // Calculate aligned size + int size = getArraySize(length, alignment, headerSize, log2ElementSize); + ConstantNode sizeNode = ConstantNode.forInt(size, graph); + tlabAllocateNode = graph.add(new TLABAllocateNode(sizeNode)); + graph.addBeforeFixed(newArrayNode, tlabAllocateNode); + InitializeArrayNode initializeNode = graph.add(new InitializeArrayNode(tlabAllocateNode, lengthNode, sizeNode, arrayType, newArrayNode.fillContents(), newArrayNode.locked())); + graph.replaceFixedWithFixed(newArrayNode, initializeNode); + } else { + Key key = new Key(allocateArrayAndInitialize). + add("alignment", alignment). + add("headerSize", headerSize). + add("log2ElementSize", log2ElementSize). + add("type", arrayType); + Arguments arguments = new Arguments().add("length", lengthNode); + SnippetTemplate template = cache.get(key, assumptions); + Debug.log("Lowering allocateArrayAndInitialize in %s: node=%s, template=%s, arguments=%s", graph, newArrayNode, template, arguments); + template.instantiate(runtime, newArrayNode, DEFAULT_REPLACER, arguments); + } + } + + @SuppressWarnings("unused") + public void lower(TLABAllocateNode tlabAllocateNode, LoweringTool tool) { + StructuredGraph graph = (StructuredGraph) tlabAllocateNode.graph(); + ValueNode size = tlabAllocateNode.size(); + Key key = new Key(allocate); + Arguments arguments = arguments("size", size); + SnippetTemplate template = cache.get(key, assumptions); + Debug.log("Lowering fastAllocate in %s: node=%s, template=%s, arguments=%s", graph, tlabAllocateNode, template, arguments); + template.instantiate(runtime, tlabAllocateNode, DEFAULT_REPLACER, arguments); + } + + @SuppressWarnings("unused") + public void lower(InitializeObjectNode initializeNode, LoweringTool tool) { + StructuredGraph graph = (StructuredGraph) initializeNode.graph(); + HotSpotResolvedJavaType type = (HotSpotResolvedJavaType) initializeNode.type(); + assert !type.isArrayClass(); + ConstantNode hub = ConstantNode.forConstant(type.klass(), runtime, graph); + int size = type.instanceSize(); + assert (size % wordSize()) == 0; + assert size >= 0; + Key key = new Key(initializeObject).add("size", size).add("fillContents", initializeNode.fillContents()).add("locked", initializeNode.locked()); + ValueNode memory = initializeNode.memory(); + Arguments arguments = arguments("memory", memory).add("hub", hub).add("prototypeMarkWord", type.prototypeMarkWord()); + SnippetTemplate template = cache.get(key, assumptions); + Debug.log("Lowering initializeObject in %s: node=%s, template=%s, arguments=%s", graph, initializeNode, template, arguments); + template.instantiate(runtime, initializeNode, DEFAULT_REPLACER, arguments); + } + + @SuppressWarnings("unused") + public void lower(InitializeArrayNode initializeNode, LoweringTool tool) { + StructuredGraph graph = (StructuredGraph) initializeNode.graph(); + HotSpotResolvedJavaType type = (HotSpotResolvedJavaType) initializeNode.type(); + ResolvedJavaType elementType = type.getComponentType(); + assert elementType != null; + ConstantNode hub = ConstantNode.forConstant(type.klass(), runtime, graph); + Kind elementKind = elementType.getKind(); + final int headerSize = elementKind.getArrayBaseOffset(); + Key key = new Key(elementKind.isObject() ? initializeObjectArray : initializePrimitiveArray).add("headerSize", headerSize).add("fillContents", initializeNode.fillContents()).add("locked", initializeNode.locked()); + ValueNode memory = initializeNode.memory(); + Arguments arguments = arguments("memory", memory).add("hub", hub).add("prototypeMarkWord", type.prototypeMarkWord()).add("size", initializeNode.size()).add("length", initializeNode.length()); + SnippetTemplate template = cache.get(key, assumptions); + Debug.log("Lowering initializeObjectArray in %s: node=%s, template=%s, arguments=%s", graph, initializeNode, template, arguments); + template.instantiate(runtime, initializeNode, DEFAULT_REPLACER, arguments); + } + + @SuppressWarnings("unused") + public void lower(NewMultiArrayNode newmultiarrayNode, LoweringTool tool) { + StructuredGraph graph = (StructuredGraph) newmultiarrayNode.graph(); + int rank = newmultiarrayNode.dimensionCount(); + ValueNode[] dims = new ValueNode[rank]; + for (int i = 0; i < newmultiarrayNode.dimensionCount(); i++) { + dims[i] = newmultiarrayNode.dimension(i); + } + HotSpotResolvedJavaType type = (HotSpotResolvedJavaType) newmultiarrayNode.type(); + ConstantNode hub = ConstantNode.forConstant(type.klass(), runtime, graph); + Key key = new Key(newmultiarray).add("dimensions", vargargs(new int[rank], StampFactory.forKind(Kind.Int))).add("rank", rank); + Arguments arguments = arguments("dimensions", dims).add("hub", hub); + SnippetTemplate template = cache.get(key, assumptions); + template.instantiate(runtime, newmultiarrayNode, DEFAULT_REPLACER, arguments); + } + } + + private static final SnippetCounter.Group countersNew = GraalOptions.SnippetCounters ? new SnippetCounter.Group("NewInstance") : null; + private static final SnippetCounter new_seqInit = new SnippetCounter(countersNew, "tlabSeqInit", "TLAB alloc with unrolled zeroing"); + private static final SnippetCounter new_loopInit = new SnippetCounter(countersNew, "tlabLoopInit", "TLAB alloc with zeroing in a loop"); + private static final SnippetCounter new_stub = new SnippetCounter(countersNew, "stub", "alloc and zeroing via stub"); + + private static final SnippetCounter.Group countersNewPrimitiveArray = GraalOptions.SnippetCounters ? new SnippetCounter.Group("NewPrimitiveArray") : null; + private static final SnippetCounter newarray_loopInit = new SnippetCounter(countersNewPrimitiveArray, "tlabLoopInit", "TLAB alloc with zeroing in a loop"); + private static final SnippetCounter newarray_stub = new SnippetCounter(countersNewPrimitiveArray, "stub", "alloc and zeroing via stub"); + + private static final SnippetCounter.Group countersNewObjectArray = GraalOptions.SnippetCounters ? new SnippetCounter.Group("NewObjectArray") : null; + private static final SnippetCounter anewarray_loopInit = new SnippetCounter(countersNewObjectArray, "tlabLoopInit", "TLAB alloc with zeroing in a loop"); + private static final SnippetCounter anewarray_stub = new SnippetCounter(countersNewObjectArray, "stub", "alloc and zeroing via stub"); +} diff -r cd2c08049dd5 -r 32408bd16b91 graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/WordTest.java --- a/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/WordTest.java Tue Nov 27 12:12:02 2012 +0100 +++ b/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/WordTest.java Tue Nov 27 12:15:18 2012 +0100 @@ -43,7 +43,7 @@ public WordTest() { TargetDescription target = Graal.getRequiredCapability(GraalCompiler.class).target; - installer = new SnippetInstaller(runtime, target, new Assumptions(false)); + installer = new SnippetInstaller(runtime, new Assumptions(false), target); } private static final ThreadLocal inliningPolicy = new ThreadLocal<>(); diff -r cd2c08049dd5 -r 32408bd16b91 graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetInstaller.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetInstaller.java Tue Nov 27 12:12:02 2012 +0100 +++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetInstaller.java Tue Nov 27 12:15:18 2012 +0100 @@ -1,213 +1,213 @@ -/* - * 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.snippets; - -import java.lang.reflect.*; -import java.util.*; -import java.util.concurrent.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.graph.Node.NodeIntrinsic; -import com.oracle.graal.java.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.nodes.java.*; -import com.oracle.graal.phases.*; -import com.oracle.graal.phases.common.*; -import com.oracle.graal.snippets.Snippet.SnippetInliningPolicy; - -/** - * Utility for snippet {@linkplain #install(Class) installation}. - */ -public class SnippetInstaller { - - private final MetaAccessProvider runtime; - private final TargetDescription target; - private final Assumptions assumptions; - private final BoxingMethodPool pool; - - /** - * A graph cache used by this installer to avoid using the compiler - * storage for each method processed during snippet installation. - * Without this, all processed methods are to be determined as - * {@linkplain InliningUtil#canIntrinsify intrinsifiable}. - */ - private final Map graphCache; - - public SnippetInstaller(MetaAccessProvider runtime, Assumptions assumptions, TargetDescription target) { - this.runtime = runtime; - this.target = target; - this.assumptions = assumptions; - this.pool = new BoxingMethodPool(runtime); - this.graphCache = new HashMap<>(); - } - - /** - * Finds all the snippet methods in a given class, builds a graph for them and - * installs the graph with the key value of {@code Graph.class} in the - * {@linkplain ResolvedJavaMethod#getCompilerStorage() compiler storage} of each method. - *

- * If {@code snippetsHolder} is annotated with {@link ClassSubstitution}, then all - * methods in the class are snippets. Otherwise, the snippets are those methods - * annotated with {@link Snippet}. - */ - public void install(Class snippetsHolder) { - if (snippetsHolder.isAnnotationPresent(ClassSubstitution.class)) { - installSubstitutions(snippetsHolder, snippetsHolder.getAnnotation(ClassSubstitution.class).value()); - } else { - installSnippets(snippetsHolder); - } - } - - private void installSnippets(Class< ? extends SnippetsInterface> clazz) { - for (Method method : clazz.getDeclaredMethods()) { - if (method.getAnnotation(Snippet.class) != null) { - int modifiers = method.getModifiers(); - if (Modifier.isAbstract(modifiers) || Modifier.isNative(modifiers)) { - throw new RuntimeException("Snippet must not be abstract or native"); - } - ResolvedJavaMethod snippet = runtime.lookupJavaMethod(method); - assert snippet.getCompilerStorage().get(Graph.class) == null; - StructuredGraph graph = makeGraph(snippet, inliningPolicy(snippet)); - //System.out.println("snippet: " + graph); - snippet.getCompilerStorage().put(Graph.class, graph); - } - } - } - - private void installSubstitutions(Class< ? extends SnippetsInterface> clazz, Class originalClazz) { - for (Method method : clazz.getDeclaredMethods()) { - if (method.getAnnotation(NodeIntrinsic.class) != null) { - continue; - } - try { - Method originalMethod = originalClazz.getDeclaredMethod(method.getName(), method.getParameterTypes()); - if (!originalMethod.getReturnType().isAssignableFrom(method.getReturnType())) { - throw new RuntimeException("Snippet has incompatible return type"); - } - int modifiers = method.getModifiers(); - if (Modifier.isAbstract(modifiers) || Modifier.isNative(modifiers)) { - throw new RuntimeException("Snippet must not be abstract or native"); - } - ResolvedJavaMethod snippet = runtime.lookupJavaMethod(method); - StructuredGraph graph = makeGraph(snippet, inliningPolicy(snippet)); - //System.out.println("snippet: " + graph); - runtime.lookupJavaMethod(originalMethod).getCompilerStorage().put(Graph.class, graph); - } catch (NoSuchMethodException e) { - throw new GraalInternalError("Could not resolve method in " + originalClazz + " to substitute with " + method, e); - } - } - } - - private static SnippetInliningPolicy inliningPolicy(ResolvedJavaMethod method) { - Class policyClass = SnippetInliningPolicy.class; - Snippet snippet = method.getAnnotation(Snippet.class); - if (snippet != null) { - policyClass = snippet.inlining(); - } - if (policyClass == SnippetInliningPolicy.class) { - return SnippetInliningPolicy.Default; - } - try { - return policyClass.getConstructor().newInstance(); - } catch (Exception e) { - throw new GraalInternalError(e); - } - } - - public StructuredGraph makeGraph(final ResolvedJavaMethod method, final SnippetInliningPolicy policy) { - StructuredGraph graph = parseGraph(method, policy); - - new SnippetIntrinsificationPhase(runtime, pool, SnippetTemplate.hasConstantParameter(method)).apply(graph); - - Debug.dump(graph, "%s: Final", method.getName()); - - return graph; - } - - private StructuredGraph parseGraph(final ResolvedJavaMethod method, final SnippetInliningPolicy policy) { - StructuredGraph graph = graphCache.get(method); - if (graph == null) { - graph = buildGraph(method, policy == null ? inliningPolicy(method) : policy); - //System.out.println("built " + graph); - graphCache.put(method, graph); - } - return graph; - } - - private StructuredGraph buildGraph(final ResolvedJavaMethod method, final SnippetInliningPolicy policy) { - final StructuredGraph graph = new StructuredGraph(method); - return Debug.scope("BuildSnippetGraph", new Object[] {method, graph}, new Callable() { - @Override - public StructuredGraph call() throws Exception { - GraphBuilderConfiguration config = GraphBuilderConfiguration.getSnippetDefault(); - GraphBuilderPhase graphBuilder = new GraphBuilderPhase(runtime, config, OptimisticOptimizations.NONE); - graphBuilder.apply(graph); - - Debug.dump(graph, "%s: %s", method.getName(), GraphBuilderPhase.class.getSimpleName()); - - new SnippetVerificationPhase().apply(graph); - - new SnippetIntrinsificationPhase(runtime, pool, true).apply(graph); - - for (Invoke invoke : graph.getInvokes()) { - MethodCallTargetNode callTarget = invoke.methodCallTarget(); - ResolvedJavaMethod callee = callTarget.targetMethod(); - if (policy.shouldInline(callee, method)) { - StructuredGraph targetGraph = parseGraph(callee, policy); - InliningUtil.inline(invoke, targetGraph, true); - Debug.dump(graph, "after inlining %s", callee); - if (GraalOptions.OptCanonicalizer) { - new WordTypeRewriterPhase(target.wordKind).apply(graph); - new CanonicalizerPhase(target, runtime, assumptions).apply(graph); - } - } - } - - new SnippetIntrinsificationPhase(runtime, pool, true).apply(graph); - - new WordTypeRewriterPhase(target.wordKind).apply(graph); - - new DeadCodeEliminationPhase().apply(graph); - if (GraalOptions.OptCanonicalizer) { - new CanonicalizerPhase(target, runtime, assumptions).apply(graph); - } - - for (LoopEndNode end : graph.getNodes(LoopEndNode.class)) { - end.disableSafepoint(); - } - - new InsertStateAfterPlaceholderPhase().apply(graph); - - if (GraalOptions.ProbabilityAnalysis) { - new DeadCodeEliminationPhase().apply(graph); - new ComputeProbabilityPhase().apply(graph); - } - return graph; - } - }); - } -} +/* + * 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.snippets; + +import java.lang.reflect.*; +import java.util.*; +import java.util.concurrent.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.graph.Node.NodeIntrinsic; +import com.oracle.graal.java.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.phases.*; +import com.oracle.graal.phases.common.*; +import com.oracle.graal.snippets.Snippet.SnippetInliningPolicy; + +/** + * Utility for snippet {@linkplain #install(Class) installation}. + */ +public class SnippetInstaller { + + private final MetaAccessProvider runtime; + private final TargetDescription target; + private final Assumptions assumptions; + private final BoxingMethodPool pool; + + /** + * A graph cache used by this installer to avoid using the compiler + * storage for each method processed during snippet installation. + * Without this, all processed methods are to be determined as + * {@linkplain InliningUtil#canIntrinsify intrinsifiable}. + */ + private final Map graphCache; + + public SnippetInstaller(MetaAccessProvider runtime, Assumptions assumptions, TargetDescription target) { + this.runtime = runtime; + this.target = target; + this.assumptions = assumptions; + this.pool = new BoxingMethodPool(runtime); + this.graphCache = new HashMap<>(); + } + + /** + * Finds all the snippet methods in a given class, builds a graph for them and + * installs the graph with the key value of {@code Graph.class} in the + * {@linkplain ResolvedJavaMethod#getCompilerStorage() compiler storage} of each method. + *

+ * If {@code snippetsHolder} is annotated with {@link ClassSubstitution}, then all + * methods in the class are snippets. Otherwise, the snippets are those methods + * annotated with {@link Snippet}. + */ + public void install(Class snippetsHolder) { + if (snippetsHolder.isAnnotationPresent(ClassSubstitution.class)) { + installSubstitutions(snippetsHolder, snippetsHolder.getAnnotation(ClassSubstitution.class).value()); + } else { + installSnippets(snippetsHolder); + } + } + + private void installSnippets(Class< ? extends SnippetsInterface> clazz) { + for (Method method : clazz.getDeclaredMethods()) { + if (method.getAnnotation(Snippet.class) != null) { + int modifiers = method.getModifiers(); + if (Modifier.isAbstract(modifiers) || Modifier.isNative(modifiers)) { + throw new RuntimeException("Snippet must not be abstract or native"); + } + ResolvedJavaMethod snippet = runtime.lookupJavaMethod(method); + assert snippet.getCompilerStorage().get(Graph.class) == null; + StructuredGraph graph = makeGraph(snippet, inliningPolicy(snippet)); + //System.out.println("snippet: " + graph); + snippet.getCompilerStorage().put(Graph.class, graph); + } + } + } + + private void installSubstitutions(Class< ? extends SnippetsInterface> clazz, Class originalClazz) { + for (Method method : clazz.getDeclaredMethods()) { + if (method.getAnnotation(NodeIntrinsic.class) != null) { + continue; + } + try { + Method originalMethod = originalClazz.getDeclaredMethod(method.getName(), method.getParameterTypes()); + if (!originalMethod.getReturnType().isAssignableFrom(method.getReturnType())) { + throw new RuntimeException("Snippet has incompatible return type"); + } + int modifiers = method.getModifiers(); + if (Modifier.isAbstract(modifiers) || Modifier.isNative(modifiers)) { + throw new RuntimeException("Snippet must not be abstract or native"); + } + ResolvedJavaMethod snippet = runtime.lookupJavaMethod(method); + StructuredGraph graph = makeGraph(snippet, inliningPolicy(snippet)); + //System.out.println("snippet: " + graph); + runtime.lookupJavaMethod(originalMethod).getCompilerStorage().put(Graph.class, graph); + } catch (NoSuchMethodException e) { + throw new GraalInternalError("Could not resolve method in " + originalClazz + " to substitute with " + method, e); + } + } + } + + private static SnippetInliningPolicy inliningPolicy(ResolvedJavaMethod method) { + Class policyClass = SnippetInliningPolicy.class; + Snippet snippet = method.getAnnotation(Snippet.class); + if (snippet != null) { + policyClass = snippet.inlining(); + } + if (policyClass == SnippetInliningPolicy.class) { + return SnippetInliningPolicy.Default; + } + try { + return policyClass.getConstructor().newInstance(); + } catch (Exception e) { + throw new GraalInternalError(e); + } + } + + public StructuredGraph makeGraph(final ResolvedJavaMethod method, final SnippetInliningPolicy policy) { + StructuredGraph graph = parseGraph(method, policy); + + new SnippetIntrinsificationPhase(runtime, pool, SnippetTemplate.hasConstantParameter(method)).apply(graph); + + Debug.dump(graph, "%s: Final", method.getName()); + + return graph; + } + + private StructuredGraph parseGraph(final ResolvedJavaMethod method, final SnippetInliningPolicy policy) { + StructuredGraph graph = graphCache.get(method); + if (graph == null) { + graph = buildGraph(method, policy == null ? inliningPolicy(method) : policy); + //System.out.println("built " + graph); + graphCache.put(method, graph); + } + return graph; + } + + private StructuredGraph buildGraph(final ResolvedJavaMethod method, final SnippetInliningPolicy policy) { + final StructuredGraph graph = new StructuredGraph(method); + return Debug.scope("BuildSnippetGraph", new Object[] {method, graph}, new Callable() { + @Override + public StructuredGraph call() throws Exception { + GraphBuilderConfiguration config = GraphBuilderConfiguration.getSnippetDefault(); + GraphBuilderPhase graphBuilder = new GraphBuilderPhase(runtime, config, OptimisticOptimizations.NONE); + graphBuilder.apply(graph); + + Debug.dump(graph, "%s: %s", method.getName(), GraphBuilderPhase.class.getSimpleName()); + + new SnippetVerificationPhase().apply(graph); + + new SnippetIntrinsificationPhase(runtime, pool, true).apply(graph); + + for (Invoke invoke : graph.getInvokes()) { + MethodCallTargetNode callTarget = invoke.methodCallTarget(); + ResolvedJavaMethod callee = callTarget.targetMethod(); + if (policy.shouldInline(callee, method)) { + StructuredGraph targetGraph = parseGraph(callee, policy); + InliningUtil.inline(invoke, targetGraph, true); + Debug.dump(graph, "after inlining %s", callee); + if (GraalOptions.OptCanonicalizer) { + new WordTypeRewriterPhase(target.wordKind).apply(graph); + new CanonicalizerPhase(target, runtime, assumptions).apply(graph); + } + } + } + + new SnippetIntrinsificationPhase(runtime, pool, true).apply(graph); + + new WordTypeRewriterPhase(target.wordKind).apply(graph); + + new DeadCodeEliminationPhase().apply(graph); + if (GraalOptions.OptCanonicalizer) { + new CanonicalizerPhase(target, runtime, assumptions).apply(graph); + } + + for (LoopEndNode end : graph.getNodes(LoopEndNode.class)) { + end.disableSafepoint(); + } + + new InsertStateAfterPlaceholderPhase().apply(graph); + + if (GraalOptions.ProbabilityAnalysis) { + new DeadCodeEliminationPhase().apply(graph); + new ComputeProbabilityPhase().apply(graph); + } + return graph; + } + }); + } +}