001/*
002 * Copyright (c) 2011, 2014, 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 jdk.internal.jvmci.hotspot;
024
025import java.nio.*;
026import java.util.*;
027import java.util.stream.*;
028import java.util.stream.Stream.Builder;
029
030import jdk.internal.jvmci.code.*;
031import jdk.internal.jvmci.code.CompilationResult.CodeAnnotation;
032import jdk.internal.jvmci.code.CompilationResult.CodeComment;
033import jdk.internal.jvmci.code.CompilationResult.DataPatch;
034import jdk.internal.jvmci.code.CompilationResult.ExceptionHandler;
035import jdk.internal.jvmci.code.CompilationResult.Infopoint;
036import jdk.internal.jvmci.code.CompilationResult.JumpTable;
037import jdk.internal.jvmci.code.CompilationResult.Mark;
038import jdk.internal.jvmci.code.CompilationResult.Site;
039import jdk.internal.jvmci.meta.Assumptions.Assumption;
040import jdk.internal.jvmci.meta.*;
041
042/**
043 * A {@link CompilationResult} with additional HotSpot-specific information required for installing
044 * the code in HotSpot's code cache.
045 */
046public abstract class HotSpotCompiledCode {
047
048    public final String name;
049    public final Site[] sites;
050    public final ExceptionHandler[] exceptionHandlers;
051    public final Comment[] comments;
052    public final Assumption[] assumptions;
053
054    public final byte[] targetCode;
055    public final int targetCodeSize;
056
057    public final byte[] dataSection;
058    public final int dataSectionAlignment;
059    public final DataPatch[] dataSectionPatches;
060
061    public final int totalFrameSize;
062    public final int customStackAreaOffset;
063
064    /**
065     * The list of the methods whose bytecodes were used as input to the compilation. If
066     * {@code null}, then the compilation did not record method dependencies. Otherwise, the first
067     * element of this array is the root method of the compilation.
068     */
069    public final ResolvedJavaMethod[] methods;
070
071    public static class Comment {
072
073        public final String text;
074        public final int pcOffset;
075
076        public Comment(int pcOffset, String text) {
077            this.text = text;
078            this.pcOffset = pcOffset;
079        }
080    }
081
082    public HotSpotCompiledCode(CompilationResult compResult) {
083        name = compResult.getName();
084        sites = getSortedSites(compResult);
085        if (compResult.getExceptionHandlers().isEmpty()) {
086            exceptionHandlers = null;
087        } else {
088            exceptionHandlers = compResult.getExceptionHandlers().toArray(new ExceptionHandler[compResult.getExceptionHandlers().size()]);
089        }
090        List<CodeAnnotation> annotations = compResult.getAnnotations();
091        comments = new Comment[annotations.size()];
092        if (!annotations.isEmpty()) {
093            for (int i = 0; i < comments.length; i++) {
094                CodeAnnotation annotation = annotations.get(i);
095                String text;
096                if (annotation instanceof CodeComment) {
097                    CodeComment codeComment = (CodeComment) annotation;
098                    text = codeComment.value;
099                } else if (annotation instanceof JumpTable) {
100                    JumpTable jumpTable = (JumpTable) annotation;
101                    text = "JumpTable [" + jumpTable.low + " .. " + jumpTable.high + "]";
102                } else {
103                    text = annotation.toString();
104                }
105                comments[i] = new Comment(annotation.position, text);
106            }
107        }
108        assumptions = compResult.getAssumptions();
109        assert validateFrames();
110
111        targetCode = compResult.getTargetCode();
112        targetCodeSize = compResult.getTargetCodeSize();
113
114        DataSection data = compResult.getDataSection();
115        data.finalizeLayout();
116        dataSection = new byte[data.getSectionSize()];
117
118        ByteBuffer buffer = ByteBuffer.wrap(dataSection).order(ByteOrder.nativeOrder());
119        Builder<DataPatch> patchBuilder = Stream.builder();
120        data.buildDataSection(buffer, patchBuilder);
121
122        dataSectionAlignment = data.getSectionAlignment();
123        dataSectionPatches = patchBuilder.build().toArray(len -> new DataPatch[len]);
124
125        totalFrameSize = compResult.getTotalFrameSize();
126        customStackAreaOffset = compResult.getCustomStackAreaOffset();
127
128        methods = compResult.getMethods();
129    }
130
131    /**
132     * Ensure that all the frames passed into HotSpot are properly formatted with an empty or
133     * illegal slot following double word slots.
134     */
135    private boolean validateFrames() {
136        for (Site site : sites) {
137            if (site instanceof Infopoint) {
138                Infopoint info = (Infopoint) site;
139                if (info.debugInfo != null) {
140                    BytecodeFrame frame = info.debugInfo.frame();
141                    assert frame == null || frame.validateFormat(false);
142                }
143            }
144        }
145        return true;
146    }
147
148    static class SiteComparator implements Comparator<Site> {
149
150        public int compare(Site s1, Site s2) {
151            if (s1.pcOffset == s2.pcOffset && (s1 instanceof Mark ^ s2 instanceof Mark)) {
152                return s1 instanceof Mark ? -1 : 1;
153            }
154            return s1.pcOffset - s2.pcOffset;
155        }
156    }
157
158    private static Site[] getSortedSites(CompilationResult target) {
159        List<?>[] lists = new List<?>[]{target.getInfopoints(), target.getDataPatches(), target.getMarks()};
160        int count = 0;
161        for (List<?> list : lists) {
162            count += list.size();
163        }
164        Site[] result = new Site[count];
165        int pos = 0;
166        for (List<?> list : lists) {
167            for (Object elem : list) {
168                result[pos++] = (Site) elem;
169            }
170        }
171        Arrays.sort(result, new SiteComparator());
172        return result;
173    }
174}