001/* 002 * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. 008 * 009 * This code is distributed in the hope that it will be useful, but WITHOUT 010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 011 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 012 * version 2 for more details (a copy is included in the LICENSE file that 013 * accompanied this code). 014 * 015 * You should have received a copy of the GNU General Public License version 016 * 2 along with this work; if not, write to the Free Software Foundation, 017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 018 * 019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 020 * or visit www.oracle.com if you need additional information or have any 021 * questions. 022 */ 023package com.oracle.graal.replacements.nodes; 024 025import java.util.*; 026 027import jdk.internal.jvmci.meta.*; 028import jdk.internal.jvmci.meta.Assumptions.*; 029 030import com.oracle.graal.compiler.common.type.*; 031import com.oracle.graal.graph.*; 032import com.oracle.graal.nodeinfo.*; 033import com.oracle.graal.nodes.CallTargetNode.InvokeKind; 034import com.oracle.graal.nodes.*; 035import com.oracle.graal.nodes.java.*; 036import com.oracle.graal.nodes.spi.*; 037import com.oracle.graal.nodes.util.*; 038import com.oracle.graal.nodes.virtual.*; 039 040@NodeInfo 041public abstract class BasicObjectCloneNode extends MacroStateSplitNode implements VirtualizableAllocation, ArrayLengthProvider { 042 043 public static final NodeClass<BasicObjectCloneNode> TYPE = NodeClass.create(BasicObjectCloneNode.class); 044 045 public BasicObjectCloneNode(NodeClass<? extends MacroNode> c, InvokeKind invokeKind, ResolvedJavaMethod targetMethod, int bci, JavaType returnType, ValueNode... arguments) { 046 super(c, invokeKind, targetMethod, bci, returnType, arguments); 047 } 048 049 @Override 050 public boolean inferStamp() { 051 Stamp objectStamp = getObject().stamp(); 052 if (objectStamp instanceof ObjectStamp) { 053 objectStamp = objectStamp.join(StampFactory.objectNonNull()); 054 } 055 return updateStamp(objectStamp); 056 } 057 058 public ValueNode getObject() { 059 return arguments.get(0); 060 } 061 062 protected static boolean isCloneableType(ResolvedJavaType type, MetaAccessProvider metaAccess) { 063 return metaAccess.lookupJavaType(Cloneable.class).isAssignableFrom(type); 064 } 065 066 /* 067 * Looks at the given stamp and determines if it is an exact type (or can be assumed to be an 068 * exact type) and if it is a cloneable type. 069 * 070 * If yes, then the exact type is returned, otherwise it returns null. 071 */ 072 protected static ResolvedJavaType getConcreteType(Stamp stamp, Assumptions assumptions, MetaAccessProvider metaAccess) { 073 if (!(stamp instanceof ObjectStamp)) { 074 return null; 075 } 076 ObjectStamp objectStamp = (ObjectStamp) stamp; 077 if (objectStamp.type() == null) { 078 return null; 079 } else if (objectStamp.isExactType()) { 080 return isCloneableType(objectStamp.type(), metaAccess) ? objectStamp.type() : null; 081 } else if (assumptions != null) { 082 AssumptionResult<ResolvedJavaType> leafConcreteSubtype = objectStamp.type().findLeafConcreteSubtype(); 083 if (leafConcreteSubtype != null && isCloneableType(leafConcreteSubtype.getResult(), metaAccess)) { 084 assumptions.record(leafConcreteSubtype); 085 return leafConcreteSubtype.getResult(); 086 } 087 } 088 return null; 089 } 090 091 @Override 092 public void virtualize(VirtualizerTool tool) { 093 ValueNode originalAlias = tool.getAlias(getObject()); 094 if (originalAlias instanceof VirtualObjectNode) { 095 VirtualObjectNode originalVirtual = (VirtualObjectNode) originalAlias; 096 if (isCloneableType(originalVirtual.type(), tool.getMetaAccessProvider())) { 097 ValueNode[] newEntryState = new ValueNode[originalVirtual.entryCount()]; 098 for (int i = 0; i < newEntryState.length; i++) { 099 newEntryState[i] = tool.getEntry(originalVirtual, i); 100 } 101 VirtualObjectNode newVirtual = originalVirtual.duplicate(); 102 tool.createVirtualObject(newVirtual, newEntryState, Collections.<MonitorIdNode> emptyList(), false); 103 tool.replaceWithVirtual(newVirtual); 104 } 105 } else { 106 ResolvedJavaType type = getConcreteType(originalAlias.stamp(), graph().getAssumptions(), tool.getMetaAccessProvider()); 107 if (type != null && !type.isArray()) { 108 VirtualInstanceNode newVirtual = createVirtualInstanceNode(type, true); 109 ResolvedJavaField[] fields = newVirtual.getFields(); 110 111 ValueNode[] state = new ValueNode[fields.length]; 112 final LoadFieldNode[] loads = new LoadFieldNode[fields.length]; 113 for (int i = 0; i < fields.length; i++) { 114 state[i] = loads[i] = new LoadFieldNode(originalAlias, fields[i]); 115 tool.addNode(loads[i]); 116 } 117 tool.createVirtualObject(newVirtual, state, Collections.<MonitorIdNode> emptyList(), false); 118 tool.replaceWithVirtual(newVirtual); 119 } 120 } 121 } 122 123 protected VirtualInstanceNode createVirtualInstanceNode(ResolvedJavaType type, boolean hasIdentity) { 124 return new VirtualInstanceNode(type, hasIdentity); 125 } 126 127 @Override 128 public ValueNode length() { 129 return GraphUtil.arrayLength(getObject()); 130 } 131}