# HG changeset patch # User Lukas Stadler # Date 1360318455 -3600 # Node ID cff55cdeea48196c3bdc03ece9e6e8c2612d7053 # Parent ebba355f5605e6448001ce342dd1b24cdc1ceff1 implement Object.clone snippets and macro node diff -r ebba355f5605 -r cff55cdeea48 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 Fri Feb 08 10:41:09 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java Fri Feb 08 11:14:15 2013 +0100 @@ -350,6 +350,9 @@ if (GraalOptions.IntrinsifyArrayCopy) { installer.installSnippets(ArrayCopySnippets.class); } + if (GraalOptions.IntrinsifyObjectClone) { + installer.installSnippets(ObjectCloneSnippets.class); + } installer.installSnippets(CheckCastSnippets.class); installer.installSnippets(InstanceOfSnippets.class); @@ -705,7 +708,7 @@ assert loadHub.kind() == wordKind; LocationNode location = LocationNode.create(LocationNode.FINAL_LOCATION, wordKind, config.hubOffset, graph); ValueNode object = loadHub.object(); - assert !object.isConstant(); + assert !object.isConstant() || object.asConstant().isNull(); ValueNode guard = tool.createNullCheckGuard(object); ReadNode hub = graph.add(new ReadNode(object, location, StampFactory.forKind(wordKind()))); hub.dependencies().add(guard); diff -r ebba355f5605 -r cff55cdeea48 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ObjectCloneNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ObjectCloneNode.java Fri Feb 08 11:14:15 2013 +0100 @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 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 java.lang.reflect.*; + +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.nodes.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; +import com.oracle.graal.nodes.virtual.*; +import com.oracle.graal.phases.*; +import com.oracle.graal.phases.common.*; +import com.oracle.graal.snippets.nodes.*; + +public class ObjectCloneNode extends MacroNode implements VirtualizableAllocation, ArrayLengthProvider { + + public ObjectCloneNode(Invoke invoke) { + super(invoke); + } + + @Override + public boolean inferStamp() { + return updateStamp(getObject().stamp()); + } + + private ValueNode getObject() { + return arguments.get(0); + } + + private Method selectSnippetMethod(LoweringTool tool) { + ResolvedJavaType type = getObject().objectStamp().type(); + if (type.isArray()) { + return ObjectCloneSnippets.arrayCloneMethod; + } else if (type.isAssignableFrom(tool.getRuntime().lookupJavaType(Object[].class))) { + // arrays are assignable to Object, Cloneable and Serializable + return ObjectCloneSnippets.genericCloneMethod; + } else { + return ObjectCloneSnippets.instanceCloneMethod; + } + } + + @Override + public void lower(LoweringTool tool) { + if (!GraalOptions.IntrinsifyObjectClone) { + super.lower(tool); + return; + } + ResolvedJavaMethod snippetMethod = tool.getRuntime().lookupJavaMethod(selectSnippetMethod(tool)); + if (Debug.isLogEnabled()) { + Debug.log("%s > Intrinsify (%s)", Debug.currentScope(), snippetMethod.getSignature().getParameterType(0, snippetMethod.getDeclaringClass()).getComponentType()); + } + + StructuredGraph snippetGraph = (StructuredGraph) snippetMethod.getCompilerStorage().get(Graph.class); + assert snippetGraph != null : "ObjectCloneSnippets should be installed"; + InvokeNode invoke = replaceWithInvoke(); + InliningUtil.inline(invoke, snippetGraph, false); + } + + private static boolean isCloneableType(ResolvedJavaType type, MetaAccessProvider metaAccess) { + return metaAccess.lookupJavaType(Cloneable.class).isAssignableFrom(type); + } + + private static ResolvedJavaType getConcreteType(ObjectStamp stamp, Assumptions assumptions) { + if (stamp.isExactType()) { + return stamp.type(); + } else { + ResolvedJavaType type = stamp.type().findUniqueConcreteSubtype(); + if (type != null) { + assumptions.recordConcreteSubtype(stamp.type(), type); + } + return type; + } + } + + @Override + public void virtualize(VirtualizerTool tool) { + State originalState = tool.getObjectState(getObject()); + if (originalState != null && originalState.getState() == EscapeState.Virtual) { + VirtualObjectNode originalVirtual = originalState.getVirtualObject(); + if (isCloneableType(originalVirtual.type(), tool.getMetaAccessProvider())) { + ValueNode[] newEntryState = new ValueNode[originalVirtual.entryCount()]; + for (int i = 0; i < newEntryState.length; i++) { + newEntryState[i] = originalState.getEntry(i); + } + VirtualObjectNode newVirtual = (VirtualObjectNode) originalVirtual.copyWithInputs(); + tool.createVirtualObject(newVirtual, newEntryState, 0); + tool.replaceWithVirtual(newVirtual); + } + } else { + ValueNode obj; + if (originalState != null) { + obj = originalState.getMaterializedValue(); + } else { + obj = tool.getReplacedValue(getObject()); + } + ResolvedJavaType type = getConcreteType(obj.objectStamp(), tool.getAssumptions()); + if (isCloneableType(type, tool.getMetaAccessProvider())) { + if (!type.isArray()) { + ResolvedJavaField[] fields = type.getInstanceFields(true); + ValueNode[] state = new ValueNode[fields.length]; + final LoadFieldNode[] loads = new LoadFieldNode[fields.length]; + for (int i = 0; i < fields.length; i++) { + state[i] = loads[i] = graph().add(new LoadFieldNode(obj, fields[i])); + } + + VirtualObjectNode newVirtual = new VirtualInstanceNode(type, fields); + final StructuredGraph structuredGraph = (StructuredGraph) graph(); + tool.customAction(new Runnable() { + + public void run() { + for (LoadFieldNode load : loads) { + structuredGraph.addBeforeFixed(ObjectCloneNode.this, load); + } + } + }); + tool.createVirtualObject(newVirtual, state, 0); + tool.replaceWithVirtual(newVirtual); + } + } + } + } + + @Override + public ValueNode length() { + if (getObject() instanceof ArrayLengthProvider) { + return ((ArrayLengthProvider) getObject()).length(); + } else { + return null; + } + } +} diff -r ebba355f5605 -r cff55cdeea48 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ObjectCloneSnippets.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ObjectCloneSnippets.java Fri Feb 08 11:14:15 2013 +0100 @@ -0,0 +1,132 @@ +/* + * 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.hotspot.snippets; + +import static com.oracle.graal.hotspot.snippets.HotSpotSnippetUtils.*; +import static com.oracle.graal.snippets.nodes.BranchProbabilityNode.*; + +import java.lang.reflect.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.phases.*; +import com.oracle.graal.snippets.*; +import com.oracle.graal.word.*; + +public class ObjectCloneSnippets implements SnippetsInterface { + + public static final Method instanceCloneMethod = getCloneMethod("instanceClone"); + public static final Method arrayCloneMethod = getCloneMethod("arrayClone"); + public static final Method genericCloneMethod = getCloneMethod("genericClone"); + + private static Method getCloneMethod(String name) { + try { + return ObjectCloneSnippets.class.getDeclaredMethod(name, Object.class); + } catch (SecurityException | NoSuchMethodException e) { + throw new GraalInternalError(e); + } + } + + private static Object instanceClone(Object src, Word hub, int layoutHelper) { + int instanceSize = layoutHelper; + Pointer memory = NewObjectSnippets.allocate(instanceSize); + Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset()); + Object result = NewObjectSnippets.initializeObject((Word) memory, hub, prototypeMarkWord, instanceSize, false, false); + + memory = Word.fromObject(result); + for (int offset = 2 * wordSize(); offset < instanceSize; offset += wordSize()) { + memory.writeWord(offset, Word.fromObject(src).readWord(offset)); + } + + return result; + } + + private static Object arrayClone(Object src, Word hub, int layoutHelper) { + int arrayLength = ArrayLengthNode.arrayLength(src); + int log2ElementSize = (layoutHelper >> layoutHelperLog2ElementSizeShift()) & layoutHelperLog2ElementSizeMask(); + int headerSize = (layoutHelper >> layoutHelperHeaderSizeShift()) & layoutHelperHeaderSizeMask(); + int sizeInBytes = NewObjectSnippets.computeArrayAllocationSize(arrayLength, wordSize(), headerSize, log2ElementSize); + + Pointer memory = NewObjectSnippets.allocate(sizeInBytes); + Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset()); + Object result = NewObjectSnippets.initializeArray((Word) memory, hub, arrayLength, sizeInBytes, prototypeMarkWord, headerSize, false, false); + + memory = Word.fromObject(result); + for (int offset = headerSize; offset < sizeInBytes; offset += wordSize()) { + memory.writeWord(offset, Word.fromObject(src).readWord(offset)); + } + return result; + } + + private static Word getAndCheckHub(Object src) { + Word hub = loadHub(src); + if (!(src instanceof Cloneable)) { + probability(DEOPT_PATH_PROBABILITY); + DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint); + } + return hub; + } + + @Snippet + public static Object instanceClone(Object src) { + instanceCloneCounter.inc(); + Word hub = getAndCheckHub(src); + return instanceClone(src, hub, hub.readInt(layoutHelperOffset())); + } + + @Snippet + public static Object arrayClone(Object src) { + arrayCloneCounter.inc(); + Word hub = getAndCheckHub(src); + int layoutHelper = hub.readInt(layoutHelperOffset()); + return arrayClone(src, hub, layoutHelper); + } + + @Snippet + public static Object genericClone(Object src) { + genericCloneCounter.inc(); + Word hub = getAndCheckHub(src); + int layoutHelper = hub.readInt(layoutHelperOffset()); + if (layoutHelper < 0) { + probability(LIKELY_PROBABILITY); + genericArrayCloneCounter.inc(); + return arrayClone(src, hub, layoutHelper); + } else { + genericInstanceCloneCounter.inc(); + return instanceClone(src, hub, layoutHelper); + } + } + + private static final SnippetCounter.Group cloneCounters = GraalOptions.SnippetCounters ? new SnippetCounter.Group("Object.clone") : null; + private static final SnippetCounter instanceCloneCounter = new SnippetCounter(cloneCounters, "instanceClone", "clone snippet for instances"); + private static final SnippetCounter arrayCloneCounter = new SnippetCounter(cloneCounters, "arrayClone", "clone snippet for arrays"); + private static final SnippetCounter genericCloneCounter = new SnippetCounter(cloneCounters, "genericClone", "clone snippet for arrays and instances"); + + private static final SnippetCounter.Group genericCloneCounters = GraalOptions.SnippetCounters ? new SnippetCounter.Group("Object.clone generic snippet") : null; + private static final SnippetCounter genericInstanceCloneCounter = new SnippetCounter(genericCloneCounters, "genericInstanceClone", "generic clone implementation took instance path"); + private static final SnippetCounter genericArrayCloneCounter = new SnippetCounter(genericCloneCounters, "genericArrayClone", "generic clone implementation took array path"); + +} diff -r ebba355f5605 -r cff55cdeea48 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ObjectSubstitutions.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ObjectSubstitutions.java Fri Feb 08 10:41:09 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ObjectSubstitutions.java Fri Feb 08 11:14:15 2013 +0100 @@ -26,7 +26,7 @@ import static com.oracle.graal.nodes.extended.UnsafeCastNode.*; import com.oracle.graal.snippets.*; -import com.oracle.graal.snippets.ClassSubstitution.MethodSubstitution; +import com.oracle.graal.snippets.ClassSubstitution.*; import com.oracle.graal.word.*; /** @@ -45,4 +45,7 @@ public static int hashCode(final Object thisObj) { return computeHashCode(thisObj); } + + @MacroSubstitution(macro = ObjectCloneNode.class, isStatic = false) + public static native Object clone(Object obj); } diff -r ebba355f5605 -r cff55cdeea48 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java Fri Feb 08 10:41:09 2013 +0100 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java Fri Feb 08 11:14:15 2013 +0100 @@ -197,6 +197,7 @@ public static boolean OptDevirtualizeInvokesOptimistically = true; // Intrinsification settings + public static boolean IntrinsifyObjectClone = true; public static boolean IntrinsifyArrayCopy = true; public static boolean IntrinsifyObjectMethods = true; public static boolean IntrinsifySystemMethods = true;