1/*
2 * Copyright (c) 2016, 2017, 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 */
23
24package jdk.tools.jaotc;
25
26import java.nio.ByteBuffer;
27import java.nio.ByteOrder;
28
29import jdk.tools.jaotc.binformat.BinaryContainer;
30import jdk.tools.jaotc.binformat.Relocation;
31import jdk.tools.jaotc.binformat.Relocation.RelocType;
32import jdk.tools.jaotc.binformat.Symbol;
33import jdk.tools.jaotc.binformat.Symbol.Binding;
34import jdk.tools.jaotc.binformat.Symbol.Kind;
35import org.graalvm.compiler.code.DataSection;
36import org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction;
37
38import jdk.vm.ci.code.TargetDescription;
39import jdk.vm.ci.code.site.ConstantReference;
40import jdk.vm.ci.code.site.DataPatch;
41import jdk.vm.ci.code.site.DataSectionReference;
42import jdk.vm.ci.code.site.Reference;
43import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant;
44import jdk.vm.ci.hotspot.HotSpotObjectConstant;
45import jdk.vm.ci.hotspot.HotSpotResolvedObjectType;
46import jdk.vm.ci.hotspot.HotSpotSentinelConstant;
47import jdk.vm.ci.meta.VMConstant;
48
49final class DataPatchProcessor {
50
51    private final TargetDescription target;
52
53    private final BinaryContainer binaryContainer;
54
55    DataPatchProcessor(DataBuilder dataBuilder) {
56        this.target = dataBuilder.getBackend().getTarget();
57        this.binaryContainer = dataBuilder.getBinaryContainer();
58    }
59
60    /**
61     * Process a {@link DataPatch} generated by the compiler and create all needed binary section
62     * constructs.
63     */
64    void process(CompiledMethodInfo methodInfo, DataPatch dataPatch) {
65        Reference reference = dataPatch.reference;
66        if (reference instanceof ConstantReference) {
67            processConstantReference(dataPatch, methodInfo);
68        } else if (reference instanceof DataSectionReference) {
69            processDataSectionReference(dataPatch, methodInfo);
70        } else {
71            throw new InternalError("Unknown data patch reference: " + reference);
72        }
73    }
74
75    private void processConstantReference(DataPatch dataPatch, CompiledMethodInfo methodInfo) {
76        HotSpotConstantLoadAction action = (HotSpotConstantLoadAction) dataPatch.note;
77        ConstantReference constantReference = (ConstantReference) dataPatch.reference;
78        assert action != null : "action should be set";
79
80        VMConstant constant = constantReference.getConstant();
81        String targetSymbol = null;
82        String gotName = null;
83        if (constant instanceof HotSpotMetaspaceConstant) {
84            HotSpotMetaspaceConstant metaspaceConstant = (HotSpotMetaspaceConstant) constant;
85            if (metaspaceConstant.asResolvedJavaType() != null) {
86                HotSpotResolvedObjectType type = metaspaceConstant.asResolvedJavaType();
87                targetSymbol = type.getName();
88                gotName = ((action == HotSpotConstantLoadAction.INITIALIZE) ? "got.init." : "got.") + targetSymbol;
89                methodInfo.addDependentKlassData(binaryContainer, type);
90            } else if (metaspaceConstant.asResolvedJavaMethod() != null && action == HotSpotConstantLoadAction.LOAD_COUNTERS) {
91                targetSymbol = "counters." + JavaMethodInfo.uniqueMethodName(metaspaceConstant.asResolvedJavaMethod());
92                gotName = "got." + targetSymbol;
93                binaryContainer.addCountersSymbol(targetSymbol);
94            }
95        } else if (constant instanceof HotSpotObjectConstant) {
96            // String constant.
97            HotSpotObjectConstant oopConstant = (HotSpotObjectConstant) constant;
98            targetSymbol = "ldc." + oopConstant.toValueString();
99            Integer offset = binaryContainer.addOopSymbol(targetSymbol);
100            gotName = "got.ldc." + offset;
101        } else if (constant instanceof HotSpotSentinelConstant) {
102            targetSymbol = "state.M" + methodInfo.getCodeId();
103            gotName = "got." + targetSymbol;
104        }
105
106        assert gotName != null : "Unknown constant type: " + constant;
107
108        InstructionDecoder decoder = InstructionDecoder.getInstructionDecoder(target);
109        decoder.decodePosition(methodInfo.getCompilationResult().getTargetCode(), dataPatch.pcOffset);
110        int instructionEndOffset = decoder.currentEndOfInstruction();
111
112        int textBaseOffset = methodInfo.getTextSectionOffset();
113        int relocOffset = textBaseOffset + instructionEndOffset;
114
115        Symbol relocationSymbol = binaryContainer.getSymbol(gotName);
116        assert relocationSymbol != null : "symbol for " + gotName + " missing";
117        Relocation reloc = new Relocation(relocOffset, RelocType.METASPACE_GOT_REFERENCE, 0, binaryContainer.getCodeContainer(), relocationSymbol);
118        binaryContainer.addRelocation(reloc);
119    }
120
121    private void processDataSectionReference(DataPatch dataPatch, CompiledMethodInfo methodInfo) {
122        DataSectionReference dataReference = (DataSectionReference) dataPatch.reference;
123
124        InstructionDecoder decoder = InstructionDecoder.getInstructionDecoder(target);
125        decoder.decodePosition(methodInfo.getCompilationResult().getTargetCode(), dataPatch.pcOffset);
126        int instructionEndOffset = decoder.currentEndOfInstruction();
127
128        int textBaseOffset = methodInfo.getTextSectionOffset();
129        int relocOffset = textBaseOffset + instructionEndOffset;
130        int dataOffset = dataReference.getOffset();
131
132        DataSection dataSection = methodInfo.getCompilationResult().getDataSection();
133        DataSection.Data data = dataSection.findData(dataReference);
134        int size = data.getSize();
135        int alignment = data.getAlignment();
136        byte[] value = new byte[size];
137        ByteBuffer buffer = ByteBuffer.wrap(value).order(ByteOrder.nativeOrder());
138        DataSection.emit(buffer, data, p -> {
139        });
140        String targetSymbol = "data.M" + methodInfo.getCodeId() + "." + dataOffset;
141        Symbol relocationSymbol = binaryContainer.getSymbol(targetSymbol);
142        if (relocationSymbol == null) {
143            int symSize = Math.max(8, size);
144            int symAlig = Math.max(8, alignment);
145            int offsetInConstantDataSection = binaryContainer.addConstantData(value, symAlig);
146            relocationSymbol = binaryContainer.getConstantDataContainer().createSymbol(offsetInConstantDataSection, Kind.OBJECT, Binding.LOCAL, symSize, targetSymbol);
147        }
148        Relocation reloc = new Relocation(relocOffset, RelocType.METASPACE_GOT_REFERENCE, 0, binaryContainer.getCodeContainer(), relocationSymbol);
149        binaryContainer.addRelocation(reloc);
150    }
151
152}
153