1/*
2 * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23package org.graalvm.compiler.nodes.memory.address;
24
25import org.graalvm.compiler.core.common.type.ObjectStamp;
26import org.graalvm.compiler.graph.Node;
27import org.graalvm.compiler.graph.NodeClass;
28import org.graalvm.compiler.graph.spi.Canonicalizable;
29import org.graalvm.compiler.graph.spi.CanonicalizerTool;
30import org.graalvm.compiler.nodeinfo.InputType;
31import org.graalvm.compiler.nodeinfo.NodeInfo;
32import org.graalvm.compiler.nodes.PiNode;
33import org.graalvm.compiler.nodes.ValueNode;
34import org.graalvm.compiler.nodes.calc.BinaryArithmeticNode;
35import org.graalvm.compiler.nodes.spi.PiPushable;
36import org.graalvm.compiler.nodes.type.StampTool;
37
38import jdk.vm.ci.meta.JavaKind;
39import jdk.vm.ci.meta.ResolvedJavaField;
40import jdk.vm.ci.meta.ResolvedJavaType;
41
42/**
43 * Represents an address that is composed of a base and an offset. The base can be either a
44 * {@link JavaKind#Object}, a word-sized integer or another pointer. The offset must be a word-sized
45 * integer.
46 */
47@NodeInfo(allowedUsageTypes = InputType.Association)
48public class OffsetAddressNode extends AddressNode implements Canonicalizable, PiPushable {
49    public static final NodeClass<OffsetAddressNode> TYPE = NodeClass.create(OffsetAddressNode.class);
50
51    @Input ValueNode base;
52    @Input ValueNode offset;
53
54    public OffsetAddressNode(ValueNode base, ValueNode offset) {
55        super(TYPE);
56        this.base = base;
57        this.offset = offset;
58    }
59
60    public ValueNode getBase() {
61        return base;
62    }
63
64    public void setBase(ValueNode base) {
65        updateUsages(this.base, base);
66        this.base = base;
67    }
68
69    public ValueNode getOffset() {
70        return offset;
71    }
72
73    public void setOffset(ValueNode offset) {
74        updateUsages(this.offset, offset);
75        this.offset = offset;
76    }
77
78    @Override
79    public Node canonical(CanonicalizerTool tool) {
80        if (base instanceof RawAddressNode) {
81            // The RawAddressNode is redundant, just directly use its input as base.
82            return new OffsetAddressNode(((RawAddressNode) base).getAddress(), offset);
83        } else if (base instanceof OffsetAddressNode) {
84            // Rewrite (&base[offset1])[offset2] to base[offset1 + offset2].
85            OffsetAddressNode b = (OffsetAddressNode) base;
86            return new OffsetAddressNode(b.getBase(), BinaryArithmeticNode.add(b.getOffset(), this.getOffset()));
87        } else {
88            return this;
89        }
90    }
91
92    @Override
93    public boolean push(PiNode parent) {
94        if (!(offset.isConstant() && parent.stamp() instanceof ObjectStamp && parent.object().stamp() instanceof ObjectStamp)) {
95            return false;
96        }
97
98        ObjectStamp piStamp = (ObjectStamp) parent.stamp();
99        ResolvedJavaType receiverType = piStamp.type();
100        if (receiverType == null) {
101            return false;
102        }
103        ResolvedJavaField field = receiverType.findInstanceFieldWithOffset(offset.asJavaConstant().asLong(), JavaKind.Void);
104        if (field == null) {
105            // field was not declared by receiverType
106            return false;
107        }
108
109        ObjectStamp valueStamp = (ObjectStamp) parent.object().stamp();
110        ResolvedJavaType valueType = StampTool.typeOrNull(valueStamp);
111        if (valueType != null && field.getDeclaringClass().isAssignableFrom(valueType)) {
112            if (piStamp.nonNull() == valueStamp.nonNull() && piStamp.alwaysNull() == valueStamp.alwaysNull()) {
113                replaceFirstInput(parent, parent.object());
114                return true;
115            }
116        }
117
118        return false;
119    }
120
121    @NodeIntrinsic
122    public static native Address address(Object base, long offset);
123}
124