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
24
25 package org.graalvm.compiler.hotspot;
26
27 import static org.graalvm.util.CollectionsUtil.anyMatch;
28
29 import java.nio.ByteBuffer;
30 import java.nio.ByteOrder;
31 import java.util.ArrayList;
32 import java.util.Collections;
33 import java.util.Comparator;
34 import java.util.EnumMap;
35 import java.util.List;
36 import java.util.Map;
37 import java.util.stream.Stream;
38 import java.util.stream.Stream.Builder;
39
40 import org.graalvm.compiler.code.CompilationResult;
41 import org.graalvm.compiler.code.CompilationResult.CodeAnnotation;
42 import org.graalvm.compiler.code.CompilationResult.CodeComment;
43 import org.graalvm.compiler.code.CompilationResult.JumpTable;
44 import org.graalvm.compiler.code.DataSection;
45 import org.graalvm.compiler.code.SourceMapping;
46 import org.graalvm.compiler.debug.GraalError;
47 import org.graalvm.compiler.graph.NodeSourcePosition;
48
49 import jdk.vm.ci.code.CodeCacheProvider;
50 import jdk.vm.ci.code.DebugInfo;
51 import jdk.vm.ci.code.StackSlot;
52 import jdk.vm.ci.code.site.ConstantReference;
53 import jdk.vm.ci.code.site.DataPatch;
54 import jdk.vm.ci.code.site.Infopoint;
55 import jdk.vm.ci.code.site.InfopointReason;
56 import jdk.vm.ci.code.site.Mark;
57 import jdk.vm.ci.code.site.Site;
58 import jdk.vm.ci.hotspot.HotSpotCompilationRequest;
59 import jdk.vm.ci.hotspot.HotSpotCompiledCode;
60 import jdk.vm.ci.hotspot.HotSpotCompiledCode.Comment;
61 import jdk.vm.ci.hotspot.HotSpotCompiledNmethod;
62 import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
63 import jdk.vm.ci.meta.Assumptions.Assumption;
64 import jdk.vm.ci.meta.ResolvedJavaMethod;
65
66 public class HotSpotCompiledCodeBuilder {
67
68 public static HotSpotCompiledCode createCompiledCode(CodeCacheProvider codeCache, ResolvedJavaMethod method, HotSpotCompilationRequest compRequest, CompilationResult compResult) {
69 String name = compResult.getName();
70
71 byte[] targetCode = compResult.getTargetCode();
72 int targetCodeSize = compResult.getTargetCodeSize();
73
74 Site[] sites = getSortedSites(codeCache, compResult);
75
76 Assumption[] assumptions = compResult.getAssumptions();
77
78 ResolvedJavaMethod[] methods = compResult.getMethods();
79
80 List<CodeAnnotation> annotations = compResult.getAnnotations();
81 Comment[] comments = new Comment[annotations.size()];
82 if (!annotations.isEmpty()) {
83 for (int i = 0; i < comments.length; i++) {
84 CodeAnnotation annotation = annotations.get(i);
85 String text;
86 if (annotation instanceof CodeComment) {
87 CodeComment codeComment = (CodeComment) annotation;
88 text = codeComment.value;
89 } else if (annotation instanceof JumpTable) {
90 JumpTable jumpTable = (JumpTable) annotation;
91 text = "JumpTable [" + jumpTable.low + " .. " + jumpTable.high + "]";
92 } else {
93 text = annotation.toString();
94 }
188 boolean s1IsInfopoint = s1 instanceof Infopoint;
189 boolean s2IsInfopoint = s2 instanceof Infopoint;
190 if (s1IsInfopoint != s2IsInfopoint) {
191 return s1IsInfopoint ? 1 : -1;
192 }
193
194 if (s1IsInfopoint) {
195 sawCollidingInfopoints = true;
196 return checkCollision((Infopoint) s1, (Infopoint) s2);
197 }
198 }
199 return s1.pcOffset - s2.pcOffset;
200 }
201 }
202
203 /**
204 * HotSpot expects sites to be presented in ascending order of PC (see
205 * {@code DebugInformationRecorder::add_new_pc_offset}). In addition, it expects
206 * {@link Infopoint} PCs to be unique.
207 */
208 private static Site[] getSortedSites(CodeCacheProvider codeCache, CompilationResult target) {
209 List<Site> sites = new ArrayList<>(
210 target.getExceptionHandlers().size() + target.getInfopoints().size() + target.getDataPatches().size() + target.getMarks().size() + target.getSourceMappings().size());
211 sites.addAll(target.getExceptionHandlers());
212 sites.addAll(target.getInfopoints());
213 sites.addAll(target.getDataPatches());
214 sites.addAll(target.getMarks());
215
216 if (codeCache.shouldDebugNonSafepoints()) {
217 /*
218 * Translate the source mapping into appropriate info points. In HotSpot only one
219 * position can really be represented and recording the end PC seems to give the best
220 * results and corresponds with what C1 and C2 do. HotSpot doesn't like to see these
221 * unless -XX:+DebugNonSafepoints is enabled, so don't emit them in that case.
222 */
223 List<Site> sourcePositionSites = new ArrayList<>();
224 for (SourceMapping source : target.getSourceMappings()) {
225 NodeSourcePosition sourcePosition = source.getSourcePosition();
226 if (sourcePosition.isPlaceholder() || sourcePosition.isSubstitution()) {
227 // HotSpot doesn't understand any of the special positions so just drop them.
228 continue;
229 }
230 assert sourcePosition.verify();
231 sourcePosition = sourcePosition.trim();
232 /*
233 * Don't add BYTECODE_POSITION info points that would potentially create conflicts.
234 * Under certain conditions the site's pc is not the pc that gets recorded by
235 * HotSpot (see @code {CodeInstaller::site_Call}). So, avoid adding any source
236 * positions that can potentially map to the same pc. To do that make sure that the
237 * source mapping doesn't contain a pc of any important Site.
238 */
239 if (sourcePosition != null && !anyMatch(sites, s -> source.contains(s.pcOffset))) {
240 sourcePositionSites.add(new Infopoint(source.getEndOffset(), new DebugInfo(sourcePosition), InfopointReason.BYTECODE_POSITION));
241
242 }
243 }
244 sites.addAll(sourcePositionSites);
245 }
246
247 SiteComparator c = new SiteComparator();
248 Collections.sort(sites, c);
249 if (c.sawCollidingInfopoints) {
250 Infopoint lastInfopoint = null;
251 List<Site> copy = new ArrayList<>(sites.size());
252 for (Site site : sites) {
253 if (site instanceof Infopoint) {
254 Infopoint info = (Infopoint) site;
255 if (lastInfopoint == null || lastInfopoint.pcOffset != info.pcOffset) {
256 lastInfopoint = info;
257 copy.add(info);
258 } else {
259 // Omit this colliding infopoint
260 assert lastInfopoint.reason.compareTo(info.reason) <= 0;
261 }
262 } else {
263 copy.add(site);
264 }
265 }
266 sites = copy;
267 }
268 return sites.toArray(new Site[sites.size()]);
269 }
270 }
|
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
24
25 package org.graalvm.compiler.hotspot;
26
27 import static org.graalvm.compiler.hotspot.HotSpotCompiledCodeBuilder.Options.ShowSubstitutionSourceInfo;
28 import static org.graalvm.util.CollectionsUtil.anyMatch;
29
30 import java.nio.ByteBuffer;
31 import java.nio.ByteOrder;
32 import java.util.ArrayList;
33 import java.util.Collections;
34 import java.util.Comparator;
35 import java.util.EnumMap;
36 import java.util.List;
37 import java.util.ListIterator;
38 import java.util.Map;
39 import java.util.stream.Stream;
40 import java.util.stream.Stream.Builder;
41
42 import org.graalvm.compiler.api.replacements.MethodSubstitution;
43 import org.graalvm.compiler.api.replacements.Snippet;
44 import org.graalvm.compiler.code.CompilationResult;
45 import org.graalvm.compiler.code.CompilationResult.CodeAnnotation;
46 import org.graalvm.compiler.code.CompilationResult.CodeComment;
47 import org.graalvm.compiler.code.CompilationResult.JumpTable;
48 import org.graalvm.compiler.code.DataSection;
49 import org.graalvm.compiler.code.SourceMapping;
50 import org.graalvm.compiler.debug.GraalError;
51 import org.graalvm.compiler.graph.NodeSourcePosition;
52 import org.graalvm.compiler.options.Option;
53 import org.graalvm.compiler.options.OptionKey;
54 import org.graalvm.compiler.options.OptionValues;
55
56 import jdk.vm.ci.code.CodeCacheProvider;
57 import jdk.vm.ci.code.DebugInfo;
58 import jdk.vm.ci.code.StackSlot;
59 import jdk.vm.ci.code.site.ConstantReference;
60 import jdk.vm.ci.code.site.DataPatch;
61 import jdk.vm.ci.code.site.Infopoint;
62 import jdk.vm.ci.code.site.InfopointReason;
63 import jdk.vm.ci.code.site.Mark;
64 import jdk.vm.ci.code.site.Site;
65 import jdk.vm.ci.hotspot.HotSpotCompilationRequest;
66 import jdk.vm.ci.hotspot.HotSpotCompiledCode;
67 import jdk.vm.ci.hotspot.HotSpotCompiledCode.Comment;
68 import jdk.vm.ci.hotspot.HotSpotCompiledNmethod;
69 import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
70 import jdk.vm.ci.meta.Assumptions.Assumption;
71 import jdk.vm.ci.meta.ResolvedJavaMethod;
72
73 public class HotSpotCompiledCodeBuilder {
74 public static class Options {
75 // @formatter:off
76 @Option(help = "Controls whether the source position information of snippets and method substitutions" +
77 " are exposed to HotSpot. Can be useful when profiling to get more precise position information.")
78 public static final OptionKey<Boolean> ShowSubstitutionSourceInfo = new OptionKey<>(false);
79 }
80
81 public static HotSpotCompiledCode createCompiledCode(CodeCacheProvider codeCache, ResolvedJavaMethod method, HotSpotCompilationRequest compRequest, CompilationResult compResult, OptionValues options) {
82 String name = compResult.getName();
83
84 byte[] targetCode = compResult.getTargetCode();
85 int targetCodeSize = compResult.getTargetCodeSize();
86
87 Site[] sites = getSortedSites(compResult, options, codeCache.shouldDebugNonSafepoints() && method != null);
88
89 Assumption[] assumptions = compResult.getAssumptions();
90
91 ResolvedJavaMethod[] methods = compResult.getMethods();
92
93 List<CodeAnnotation> annotations = compResult.getAnnotations();
94 Comment[] comments = new Comment[annotations.size()];
95 if (!annotations.isEmpty()) {
96 for (int i = 0; i < comments.length; i++) {
97 CodeAnnotation annotation = annotations.get(i);
98 String text;
99 if (annotation instanceof CodeComment) {
100 CodeComment codeComment = (CodeComment) annotation;
101 text = codeComment.value;
102 } else if (annotation instanceof JumpTable) {
103 JumpTable jumpTable = (JumpTable) annotation;
104 text = "JumpTable [" + jumpTable.low + " .. " + jumpTable.high + "]";
105 } else {
106 text = annotation.toString();
107 }
201 boolean s1IsInfopoint = s1 instanceof Infopoint;
202 boolean s2IsInfopoint = s2 instanceof Infopoint;
203 if (s1IsInfopoint != s2IsInfopoint) {
204 return s1IsInfopoint ? 1 : -1;
205 }
206
207 if (s1IsInfopoint) {
208 sawCollidingInfopoints = true;
209 return checkCollision((Infopoint) s1, (Infopoint) s2);
210 }
211 }
212 return s1.pcOffset - s2.pcOffset;
213 }
214 }
215
216 /**
217 * HotSpot expects sites to be presented in ascending order of PC (see
218 * {@code DebugInformationRecorder::add_new_pc_offset}). In addition, it expects
219 * {@link Infopoint} PCs to be unique.
220 */
221 private static Site[] getSortedSites(CompilationResult target, OptionValues options, boolean includeSourceInfo) {
222 List<Site> sites = new ArrayList<>(
223 target.getExceptionHandlers().size() + target.getInfopoints().size() + target.getDataPatches().size() + target.getMarks().size() + target.getSourceMappings().size());
224 sites.addAll(target.getExceptionHandlers());
225 sites.addAll(target.getInfopoints());
226 sites.addAll(target.getDataPatches());
227 sites.addAll(target.getMarks());
228
229 if (includeSourceInfo) {
230 /*
231 * Translate the source mapping into appropriate info points. In HotSpot only one
232 * position can really be represented and recording the end PC seems to give the best
233 * results and corresponds with what C1 and C2 do. HotSpot doesn't like to see these
234 * unless -XX:+DebugNonSafepoints is enabled, so don't emit them in that case.
235 */
236
237 List<SourceMapping> sourceMappings = new ArrayList<>();
238 ListIterator<SourceMapping> sourceMappingListIterator = target.getSourceMappings().listIterator();
239 if (sourceMappingListIterator.hasNext()) {
240 SourceMapping currentSource = sourceMappingListIterator.next();
241 NodeSourcePosition sourcePosition = currentSource.getSourcePosition();
242 if (!sourcePosition.isPlaceholder() && !sourcePosition.isSubstitution()) {
243 sourceMappings.add(currentSource);
244 }
245 while (sourceMappingListIterator.hasNext()) {
246 SourceMapping nextSource = sourceMappingListIterator.next();
247 assert currentSource.getStartOffset() <= nextSource.getStartOffset() : "Must be presorted";
248 currentSource = nextSource;
249 sourcePosition = currentSource.getSourcePosition();
250 if (!sourcePosition.isPlaceholder() && !sourcePosition.isSubstitution()) {
251 sourceMappings.add(currentSource);
252 }
253 }
254 }
255
256 /*
257 * Don't add BYTECODE_POSITION info points that would potentially create conflicts.
258 * Under certain conditions the site's pc is not the pc that gets recorded by HotSpot
259 * (see @code {CodeInstaller::site_Call}). So, avoid adding any source positions that
260 * can potentially map to the same pc. To do that the following code makes sure that the
261 * source mapping doesn't contain a pc of any important Site.
262 */
263 sites.sort(new SiteComparator());
264
265 ListIterator<Site> siteListIterator = sites.listIterator();
266 sourceMappingListIterator = sourceMappings.listIterator();
267
268 List<Site> sourcePositionSites = new ArrayList<>();
269 Site site = null;
270
271 // Iterate over sourceMappings and sites in parallel. Create source position infopoints
272 // only for source mappings that don't have any sites inside their intervals.
273 while (sourceMappingListIterator.hasNext()) {
274 SourceMapping source = sourceMappingListIterator.next();
275
276 // Skip sites before the current source mapping
277 if (site == null || site.pcOffset < source.getStartOffset()) {
278 while (siteListIterator.hasNext()) {
279 site = siteListIterator.next();
280 if (site.pcOffset >= source.getStartOffset()) {
281 break;
282 }
283 }
284 }
285 assert !siteListIterator.hasNext() || site.pcOffset >= source.getStartOffset();
286 if (site != null && source.getStartOffset() <= site.pcOffset && site.pcOffset <= source.getEndOffset()) {
287 // Conflicting source mapping, skip it.
288 continue;
289 } else {
290 // Since the sites are sorted there can not be any more sites in this interval.
291 }
292 assert !siteListIterator.hasNext() || site.pcOffset > source.getEndOffset();
293 // Good source mapping. Create an infopoint and add it to the list.
294 NodeSourcePosition sourcePosition = source.getSourcePosition();
295 assert sourcePosition.verify();
296 if (!ShowSubstitutionSourceInfo.getValue(options)) {
297 sourcePosition = sourcePosition.trim();
298 assert verifyTrim(sourcePosition);
299 }
300 if (sourcePosition != null) {
301 assert !anyMatch(sites, s -> source.getStartOffset() <= s.pcOffset && s.pcOffset <= source.getEndOffset());
302 sourcePositionSites.add(new Infopoint(source.getEndOffset(), new DebugInfo(sourcePosition), InfopointReason.BYTECODE_POSITION));
303 }
304 }
305
306 sites.addAll(sourcePositionSites);
307 }
308
309 SiteComparator c = new SiteComparator();
310 Collections.sort(sites, c);
311
312 if (c.sawCollidingInfopoints) {
313 Infopoint lastInfopoint = null;
314 List<Site> copy = new ArrayList<>(sites.size());
315 for (Site site : sites) {
316 if (site instanceof Infopoint) {
317 Infopoint info = (Infopoint) site;
318 if (lastInfopoint == null || lastInfopoint.pcOffset != info.pcOffset) {
319 lastInfopoint = info;
320 copy.add(info);
321 } else {
322 // Omit this colliding infopoint
323 assert lastInfopoint.reason.compareTo(info.reason) <= 0;
324 }
325 } else {
326 copy.add(site);
327 }
328 }
329 sites = copy;
330 }
331
332 return sites.toArray(new Site[sites.size()]);
333 }
334
335 private static boolean verifyTrim(NodeSourcePosition sourcePosition) {
336 for (NodeSourcePosition sp = sourcePosition; sp != null; sp = sp.getCaller()) {
337 assert (sp.getMethod().getAnnotation(Snippet.class) == null && sp.getMethod().getAnnotation(MethodSubstitution.class) == null);
338 }
339 return true;
340 }
341 }
|