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}