Skip to content

Commit 4e6f52c

Browse files
committed
[GR-66413] Do not align code of cold methods to save code size
PullRequest: graal/21215
2 parents b5d1007 + 444a542 commit 4e6f52c

File tree

5 files changed

+76
-28
lines changed

5 files changed

+76
-28
lines changed

substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/SubstrateAArch64Backend.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
import com.oracle.svm.core.deopt.Deoptimizer;
5353
import com.oracle.svm.core.graal.code.AssignedLocation;
5454
import com.oracle.svm.core.graal.code.PatchConsumerFactory;
55+
import com.oracle.svm.core.graal.code.SharedCompilationResult;
5556
import com.oracle.svm.core.graal.code.SubstrateBackend;
5657
import com.oracle.svm.core.graal.code.SubstrateCallingConvention;
5758
import com.oracle.svm.core.graal.code.SubstrateCallingConventionKind;
@@ -1326,6 +1327,10 @@ public CompilationResultBuilder newCompilationResultBuilder(LIRGenerationResult
13261327
CompilationResultBuilder crb = factory.createBuilder(getProviders(), lirGenResult.getFrameMap(), masm, dataBuilder, frameContext, options, debug, compilationResult,
13271328
uncompressedNullRegister, lir);
13281329
crb.setTotalFrameSize(lirGenResult.getFrameMap().totalFrameSize());
1330+
if (SubstrateUtil.HOSTED) {
1331+
var sharedCompilationResult = (SharedCompilationResult) compilationResult;
1332+
sharedCompilationResult.setCodeAlignment(SubstrateOptions.codeAlignment(options));
1333+
}
13291334
return crb;
13301335
}
13311336

substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/SubstrateAMD64Backend.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1900,6 +1900,9 @@ public CompilationResultBuilder newCompilationResultBuilder(LIRGenerationResult
19001900
var sharedCompilationResult = (SharedCompilationResult) compilationResult;
19011901
var substrateAMD64FrameMap = (SubstrateAMD64FrameMap) frameMap;
19021902
sharedCompilationResult.setFrameSize(substrateAMD64FrameMap.frameSize());
1903+
if (SubstrateUtil.HOSTED) {
1904+
sharedCompilationResult.setCodeAlignment(SubstrateOptions.codeAlignment(options));
1905+
}
19031906
if (substrateAMD64FrameMap.needsFramePointer()) {
19041907
sharedCompilationResult.setFramePointerSaveAreaOffset(substrateAMD64FrameMap.getFramePointerSaveAreaOffset());
19051908
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@
8181
import com.oracle.svm.util.ReflectionUtil;
8282

8383
import jdk.graal.compiler.api.replacements.Fold;
84+
import jdk.graal.compiler.asm.amd64.AMD64Assembler;
8485
import jdk.graal.compiler.core.common.GraalOptions;
8586
import jdk.graal.compiler.options.Option;
8687
import jdk.graal.compiler.options.OptionKey;
@@ -390,10 +391,14 @@ public static void configureOs(EconomicMap<OptionKey<?>, Object> values) {
390391
disable(GraalOptions.PartialUnroll, values);
391392

392393
/*
393-
* Do not align loop headers to further reduce code size.
394+
* Do not align code to further reduce code size.
394395
*/
396+
ConcealedOptions.CodeAlignment.update(values, 1);
395397
GraalOptions.LoopHeaderAlignment.update(values, 0);
396398
GraalOptions.IsolatedLoopHeaderAlignment.update(values, 0);
399+
if (ConfigurationValues.getTarget().arch instanceof AMD64) {
400+
disable(AMD64Assembler.Options.UseBranchesWithin32ByteBoundary, values);
401+
}
397402

398403
/*
399404
* Do not run PEA - it can fan out allocations too much.
@@ -1050,12 +1055,18 @@ public static int codeAlignment() {
10501055
return value;
10511056
}
10521057

1053-
if (ConfigurationValues.getTarget().arch instanceof AMD64 && optimizationLevel() != OptimizationLevel.SIZE) {
1058+
if (ConfigurationValues.getTarget().arch instanceof AMD64) {
10541059
return 32;
10551060
}
10561061
return 16;
10571062
}
10581063

1064+
@Platforms(Platform.HOSTED_ONLY.class)
1065+
public static int codeAlignment(OptionValues options) {
1066+
int value = ConcealedOptions.CodeAlignment.getValue(options);
1067+
return value > 0 ? value : codeAlignment();
1068+
}
1069+
10591070
@Option(help = "Determines if VM internal threads (e.g., a dedicated VM operation or reference handling thread) are allowed in this image.", type = OptionType.Expert) //
10601071
public static final HostedOptionKey<Boolean> AllowVMInternalThreads = new HostedOptionKey<>(true);
10611072

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/code/SharedCompilationResult.java

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -24,13 +24,17 @@
2424
*/
2525
package com.oracle.svm.core.graal.code;
2626

27+
import com.oracle.svm.core.SubstrateOptions;
28+
import com.oracle.svm.core.util.VMError;
2729
import jdk.graal.compiler.code.CompilationResult;
2830
import jdk.graal.compiler.core.common.CompilationIdentifier;
31+
import jdk.graal.compiler.core.common.NumUtil;
2932

3033
/** Base class common to both hosted and runtime compilations. */
3134
public abstract class SharedCompilationResult extends CompilationResult {
3235
private int frameSize = -1;
3336
private int framePointerSaveAreaOffset = -1;
37+
private int codeAlignment = -1;
3438

3539
public SharedCompilationResult(CompilationIdentifier compilationId, String name) {
3640
super(compilationId, name);
@@ -52,4 +56,20 @@ public int getFramePointerSaveAreaOffset() {
5256
public void setFramePointerSaveAreaOffset(int framePointerSaveAreaOffset) {
5357
this.framePointerSaveAreaOffset = framePointerSaveAreaOffset;
5458
}
59+
60+
public static int getCodeAlignment(CompilationResult compilation) {
61+
int result;
62+
if (compilation instanceof SharedCompilationResult s) {
63+
result = s.codeAlignment;
64+
} else {
65+
result = SubstrateOptions.codeAlignment();
66+
}
67+
VMError.guarantee(result > 0 && NumUtil.isUnsignedPowerOf2(result), "invalid alignment %d", result);
68+
return result;
69+
}
70+
71+
public void setCodeAlignment(int codeAlignment) {
72+
VMError.guarantee(codeAlignment > 0 && NumUtil.isUnsignedPowerOf2(codeAlignment), "invalid alignment %d", codeAlignment);
73+
this.codeAlignment = codeAlignment;
74+
}
5575
}

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/LIRNativeImageCodeCache.java

Lines changed: 34 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -39,6 +39,7 @@
3939
import com.oracle.objectfile.ObjectFile;
4040
import com.oracle.svm.core.SubstrateOptions;
4141
import com.oracle.svm.core.config.ConfigurationValues;
42+
import com.oracle.svm.core.graal.code.SharedCompilationResult;
4243
import com.oracle.svm.core.util.VMError;
4344
import com.oracle.svm.hosted.DeadlockWatchdog;
4445
import com.oracle.svm.hosted.code.HostedDirectCallTrampolineSupport;
@@ -96,9 +97,9 @@ public int codeSizeFor(HostedMethod method) {
9697
if (orderedTrampolineMap.containsKey(method)) {
9798
List<Pair<HostedMethod, Integer>> trampolineList = orderedTrampolineMap.get(method);
9899
int lastTrampolineStart = trampolineList.get(trampolineList.size() - 1).getRight();
99-
methodEnd = computeNextMethodStart(lastTrampolineStart, HostedDirectCallTrampolineSupport.singleton().getTrampolineSize());
100+
methodEnd = addOffset(lastTrampolineStart, HostedDirectCallTrampolineSupport.singleton().getTrampolineSize());
100101
} else {
101-
methodEnd = computeNextMethodStart(methodStart, compilationResultFor(method).getTargetCodeSize());
102+
methodEnd = addOffset(methodStart, compilationResultFor(method).getTargetCodeSize());
102103
}
103104

104105
return methodEnd - methodStart;
@@ -112,22 +113,22 @@ private boolean verifyMethodLayout() {
112113
CompilationResult compilation = entry.getRight();
113114

114115
int methodStart = method.getCodeAddressOffset();
116+
currentPos = align(currentPos, SharedCompilationResult.getCodeAlignment(compilation));
115117
assert currentPos == methodStart;
116118

117-
currentPos += compilation.getTargetCodeSize();
119+
currentPos = addOffset(currentPos, compilation.getTargetCodeSize());
118120

119121
if (orderedTrampolineMap.containsKey(method)) {
120122
for (var trampoline : orderedTrampolineMap.get(method)) {
121123
int trampolineOffset = trampoline.getRight();
122124

123-
currentPos = NumUtil.roundUp(currentPos, trampolineSupport.getTrampolineAlignment());
125+
currentPos = align(currentPos, trampolineSupport.getTrampolineAlignment());
124126
assert trampolineOffset == currentPos;
125127

126128
currentPos += trampolineSupport.getTrampolineSize();
127129
}
128130
}
129131

130-
currentPos = computeNextMethodStart(currentPos, 0);
131132
int size = currentPos - method.getCodeAddressOffset();
132133
assert codeSizeFor(method) == size;
133134
}
@@ -148,13 +149,14 @@ public void layoutMethods(DebugContext debug, BigBang bb) {
148149
for (Pair<HostedMethod, CompilationResult> entry : getOrderedCompilations()) {
149150
HostedMethod method = entry.getLeft();
150151
CompilationResult compilation = entry.getRight();
152+
curPos = align(curPos, SharedCompilationResult.getCodeAlignment(compilation));
151153

152154
if (!trampolineSupport.mayNeedTrampolines()) {
153155
method.setCodeAddressOffset(curPos);
154156
} else {
155157
curOffsetMap.put(method, curPos);
156158
}
157-
curPos = computeNextMethodStart(curPos, compilation.getTargetCodeSize());
159+
curPos = addOffset(curPos, compilation.getTargetCodeSize());
158160
}
159161

160162
if (trampolineSupport.mayNeedTrampolines()) {
@@ -168,7 +170,7 @@ public void layoutMethods(DebugContext debug, BigBang bb) {
168170
int methodStartOffset = curOffsetMap.get(method);
169171
method.setCodeAddressOffset(methodStartOffset);
170172
Map<HostedMethod, Integer> trampolines = trampolineMap.get(method);
171-
if (trampolines.size() != 0) {
173+
if (!trampolines.isEmpty()) {
172174
// assign an offset to each trampoline
173175
List<Pair<HostedMethod, Integer>> sortedTrampolines = new ArrayList<>(trampolines.size());
174176
int position = methodStartOffset + pair.getRight().getTargetCodeSize();
@@ -177,10 +179,10 @@ public void layoutMethods(DebugContext debug, BigBang bb) {
177179
* positions.
178180
*/
179181
for (HostedMethod callTarget : trampolines.keySet().toArray(HostedMethod.EMPTY_ARRAY)) {
180-
position = NumUtil.roundUp(position, trampolineSupport.getTrampolineAlignment());
182+
position = align(position, trampolineSupport.getTrampolineAlignment());
181183
trampolines.put(callTarget, position);
182184
sortedTrampolines.add(Pair.create(callTarget, position));
183-
position += trampolineSupport.getTrampolineSize();
185+
position = addOffset(position, trampolineSupport.getTrampolineSize());
184186
}
185187
orderedTrampolineMap.put(method, sortedTrampolines);
186188
}
@@ -192,15 +194,16 @@ public void layoutMethods(DebugContext debug, BigBang bb) {
192194
Pair<HostedMethod, CompilationResult> lastCompilation = getLastCompilation();
193195
HostedMethod lastMethod = lastCompilation.getLeft();
194196

195-
// the total code size is the hypothetical start of the next method
197+
// the total code size is aligned up to SubstrateOptions.codeAlignment()
196198
int totalSize;
197199
if (orderedTrampolineMap.containsKey(lastMethod)) {
198200
var trampolines = orderedTrampolineMap.get(lastMethod);
199201
int lastTrampolineStart = trampolines.get(trampolines.size() - 1).getRight();
200-
totalSize = computeNextMethodStart(lastTrampolineStart, trampolineSupport.getTrampolineSize());
202+
totalSize = addOffset(lastTrampolineStart, trampolineSupport.getTrampolineSize());
201203
} else {
202-
totalSize = computeNextMethodStart(lastCompilation.getLeft().getCodeAddressOffset(), lastCompilation.getRight().getTargetCodeSize());
204+
totalSize = addOffset(lastCompilation.getLeft().getCodeAddressOffset(), lastCompilation.getRight().getTargetCodeSize());
203205
}
206+
totalSize = align(totalSize, SubstrateOptions.codeAlignment());
204207

205208
setCodeAreaSize(totalSize);
206209

@@ -209,14 +212,21 @@ public void layoutMethods(DebugContext debug, BigBang bb) {
209212
}
210213
}
211214

212-
private static int computeNextMethodStart(int current, int addend) {
213-
int result;
214-
try {
215-
result = NumUtil.roundUp(Math.addExact(current, addend), SubstrateOptions.codeAlignment());
216-
} catch (ArithmeticException e) {
215+
private static int align(int current, int alignment) {
216+
VMError.guarantee(current >= 0 && alignment > 0 && NumUtil.isUnsignedPowerOf2(alignment), "invalid argument %d - %d", current, alignment);
217+
int result = NumUtil.roundUp(current, alignment);
218+
if (result < current) {
217219
throw VMError.shouldNotReachHere("Code size is larger than 2GB");
218220
}
221+
return result;
222+
}
219223

224+
private static int addOffset(int current, int offset) {
225+
VMError.guarantee(current >= 0 && offset >= 0, "invalid argument %d - %d", current, offset);
226+
int result = current + offset;
227+
if (result < 0) {
228+
throw VMError.shouldNotReachHere("Code size is larger than 2GB");
229+
}
220230
return result;
221231
}
222232

@@ -236,21 +246,22 @@ private void addDirectCallTrampolines(Map<HostedMethod, Integer> curOffsetMap) {
236246
for (Pair<HostedMethod, CompilationResult> entry : getOrderedCompilations()) {
237247
HostedMethod caller = entry.getLeft();
238248
CompilationResult compilation = entry.getRight();
249+
curPos = align(curPos, SharedCompilationResult.getCodeAlignment(compilation));
239250

240251
int originalStart = curOffsetMap.get(caller);
241252
int newStart = curPos;
242253
curOffsetMap.put(caller, newStart);
243254

244255
// move curPos to the end of the method code
245-
curPos += compilation.getTargetCodeSize();
256+
curPos = addOffset(curPos, compilation.getTargetCodeSize());
246257
int newEnd = curPos;
247258

248259
Map<HostedMethod, Integer> trampolines = trampolineMap.computeIfAbsent(caller, k -> new HashMap<>());
249260

250261
// update curPos to account for current trampolines
251262
for (int j = 0; j < trampolines.size(); j++) {
252-
curPos = NumUtil.roundUp(curPos, trampolineSupport.getTrampolineAlignment());
253-
curPos += trampolineSupport.getTrampolineSize();
263+
curPos = align(curPos, trampolineSupport.getTrampolineAlignment());
264+
curPos = addOffset(curPos, trampolineSupport.getTrampolineSize());
254265
}
255266
for (Infopoint infopoint : compilation.getInfopoints()) {
256267
if (infopoint instanceof Call && ((Call) infopoint).direct) {
@@ -289,13 +300,11 @@ private void addDirectCallTrampolines(Map<HostedMethod, Integer> curOffsetMap) {
289300
// need to add another trampoline
290301
changed = true;
291302
trampolines.put(callee, 0);
292-
curPos = NumUtil.roundUp(curPos, trampolineSupport.getTrampolineAlignment());
293-
curPos += trampolineSupport.getTrampolineSize();
303+
curPos = align(curPos, trampolineSupport.getTrampolineAlignment());
304+
curPos = addOffset(curPos, trampolineSupport.getTrampolineSize());
294305
}
295306
}
296307
}
297-
// align curPos for start of next method
298-
curPos = computeNextMethodStart(curPos, 0);
299308
callerCompilationNum++;
300309
}
301310

0 commit comments

Comments
 (0)