Skip to content

Commit 12ddc84

Browse files
author
Aleksandar Gradinac
committed
[GR-40476] Introduce a mechanism for dynamic method address resolution.
PullRequest: graal/12991
2 parents 8d949c9 + 5157276 commit 12ddc84

File tree

20 files changed

+329
-28
lines changed

20 files changed

+329
-28
lines changed

compiler/src/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64Assembler.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3702,6 +3702,11 @@ public final void push(Register src) {
37023702
emitByte(0x50 + encode(src));
37033703
}
37043704

3705+
public final void push(int imm32) {
3706+
emitByte(0x68);
3707+
emitInt(imm32);
3708+
}
3709+
37053710
public void pushfq() {
37063711
emitByte(0x9c);
37073712
}

substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFUserDefinedSection.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ public void markRelocationSite(int offset, ByteBuffer bb, ObjectFile.RelocationK
154154
ELFRelocationSection rs = (ELFRelocationSection) getOrCreateRelocationElement(addend);
155155
assert symbolName != null;
156156
ELFSymtab.Entry ent = syms.getSymbol(symbolName);
157-
assert ent != null;
157+
assert ent != null : "Symbol name not defined: " + symbolName;
158158
rs.addEntry(this, offset, ELFMachine.getRelocation(getOwner().getMachine(), k), ent, addend);
159159
}
160160
}

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

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@
3939

4040
import java.util.Collection;
4141
import java.util.EnumSet;
42+
import java.util.function.BiConsumer;
43+
import java.util.function.Function;
4244

4345
import org.graalvm.compiler.asm.Label;
4446
import org.graalvm.compiler.asm.amd64.AMD64Address;
@@ -268,23 +270,29 @@ public static class SubstrateAMD64IndirectCallOp extends AMD64Call.IndirectCallO
268270

269271
private final boolean destroysCallerSavedRegisters;
270272
@Temp({REG, OperandFlag.ILLEGAL}) private Value exceptionTemp;
273+
private final BiConsumer<CompilationResultBuilder, Integer> offsetRecorder;
271274

272275
public SubstrateAMD64IndirectCallOp(ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, Value targetAddress,
273-
LIRFrameState state, Value javaFrameAnchor, Value javaFrameAnchorTemp, int newThreadStatus, boolean destroysCallerSavedRegisters, Value exceptionTemp) {
276+
LIRFrameState state, Value javaFrameAnchor, Value javaFrameAnchorTemp, int newThreadStatus, boolean destroysCallerSavedRegisters, Value exceptionTemp,
277+
BiConsumer<CompilationResultBuilder, Integer> offsetRecorder) {
274278
super(TYPE, callTarget, result, parameters, temps, targetAddress, state);
275279
this.newThreadStatus = newThreadStatus;
276280
this.javaFrameAnchor = javaFrameAnchor;
277281
this.javaFrameAnchorTemp = javaFrameAnchorTemp;
278282
this.destroysCallerSavedRegisters = destroysCallerSavedRegisters;
279283
this.exceptionTemp = exceptionTemp;
284+
this.offsetRecorder = offsetRecorder;
280285

281286
assert differentRegisters(parameters, temps, targetAddress, javaFrameAnchor, javaFrameAnchorTemp);
282287
}
283288

284289
@Override
285290
public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
286291
maybeTransitionToNative(crb, masm, javaFrameAnchor, javaFrameAnchorTemp, state, newThreadStatus);
287-
AMD64Call.indirectCall(crb, masm, asRegister(targetAddress), callTarget, state);
292+
int offset = AMD64Call.indirectCall(crb, masm, asRegister(targetAddress), callTarget, state);
293+
if (offsetRecorder != null) {
294+
offsetRecorder.accept(crb, offset);
295+
}
288296
}
289297

290298
@Override
@@ -635,7 +643,7 @@ protected void emitForeignCallOp(ForeignCallLinkage linkage, Value targetAddress
635643
AllocatableValue targetRegister = AMD64.rax.asValue(FrameAccess.getWordStamp().getLIRKind(getLIRKindTool()));
636644
emitMove(targetRegister, targetAddress);
637645
append(new SubstrateAMD64IndirectCallOp(targetMethod, result, arguments, temps, targetRegister, info,
638-
Value.ILLEGAL, Value.ILLEGAL, StatusSupport.STATUS_ILLEGAL, getDestroysCallerSavedRegisters(targetMethod), Value.ILLEGAL));
646+
Value.ILLEGAL, Value.ILLEGAL, StatusSupport.STATUS_ILLEGAL, getDestroysCallerSavedRegisters(targetMethod), Value.ILLEGAL, null));
639647
} else {
640648
assert targetAddress == null;
641649
append(new SubstrateAMD64DirectCallOp(targetMethod, result, arguments, temps, info, Value.ILLEGAL,
@@ -817,10 +825,16 @@ public Register getHeapBaseRegister() {
817825

818826
public final class SubstrateAMD64NodeLIRBuilder extends AMD64NodeLIRBuilder implements SubstrateNodeLIRBuilder {
819827

828+
private Function<IndirectCallTargetNode, BiConsumer<CompilationResultBuilder, Integer>> indirectCallOffsetRecorderFactory = node -> null;
829+
820830
public SubstrateAMD64NodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool gen, AMD64NodeMatchRules nodeMatchRules) {
821831
super(graph, gen, nodeMatchRules);
822832
}
823833

834+
public void setIndirectCallOffsetRecorderFactory(Function<IndirectCallTargetNode, BiConsumer<CompilationResultBuilder, Integer>> indirectCallOffsetRecorderFactory) {
835+
this.indirectCallOffsetRecorderFactory = indirectCallOffsetRecorderFactory;
836+
}
837+
824838
@Override
825839
public void visitSafepointNode(SafepointNode node) {
826840
throw shouldNotReachHere("handled by lowering");
@@ -943,7 +957,7 @@ protected void emitIndirectCall(IndirectCallTargetNode callTarget, Value result,
943957
vzeroupperBeforeCall((SubstrateAMD64LIRGenerator) getLIRGeneratorTool(), parameters, callState, (SharedMethod) targetMethod);
944958
append(new SubstrateAMD64IndirectCallOp(targetMethod, result, parameters, temps, targetAddress, callState,
945959
setupJavaFrameAnchor(callTarget), setupJavaFrameAnchorTemp(callTarget), getNewThreadStatus(callTarget),
946-
getDestroysCallerSavedRegisters(targetMethod), getExceptionTemp(callTarget)));
960+
getDestroysCallerSavedRegisters(targetMethod), getExceptionTemp(callTarget), indirectCallOffsetRecorderFactory.apply(callTarget)));
947961
}
948962

949963
protected void emitComputedIndirectCall(ComputedIndirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) {

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,4 +335,8 @@ public RegisterArray filterAllocatableRegisters(PlatformKind kind, RegisterArray
335335

336336
return new RegisterArray(list);
337337
}
338+
339+
public RegisterArray getJavaGeneralParameterRegs() {
340+
return javaGeneralParameterRegs;
341+
}
338342
}

substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/headers/Errno.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,9 @@ public class Errno {
7070
@CConstant
7171
public static native int ENOMEM();
7272

73+
@CConstant
74+
public static native int EEXIST();
75+
7376
@CFunction
7477
public static native CCharPointer strerror(int errnum);
7578
}

substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/headers/Mman.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@
3030
import org.graalvm.nativeimage.c.constant.CConstant;
3131
import org.graalvm.nativeimage.c.function.CFunction;
3232
import org.graalvm.nativeimage.c.function.CFunction.Transition;
33+
import org.graalvm.nativeimage.c.function.CLibrary;
34+
import org.graalvm.nativeimage.c.type.CCharPointer;
35+
import org.graalvm.nativeimage.c.type.CConst;
3336
import org.graalvm.word.Pointer;
3437
import org.graalvm.word.PointerBase;
3538
import org.graalvm.word.UnsignedWord;
@@ -91,5 +94,15 @@ public static class NoTransitions {
9194

9295
@CFunction(transition = Transition.NO_TRANSITION)
9396
public static native int mprotect(PointerBase addr, UnsignedWord len, int prot);
97+
98+
@CFunction(transition = Transition.NO_TRANSITION)
99+
@Platforms(Platform.LINUX.class)
100+
@CLibrary("rt")
101+
public static native int shm_open(@CConst CCharPointer name, int oflag, int mode);
102+
103+
@CFunction(transition = Transition.NO_TRANSITION)
104+
@Platforms(Platform.LINUX.class)
105+
@CLibrary("rt")
106+
public static native int shm_unlink(@CConst CCharPointer name);
94107
}
95108
}

substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/headers/Unistd.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,5 +134,10 @@ public static class NoTransitions {
134134
@CFunction(transition = Transition.NO_TRANSITION)
135135
public static native int getpagesize();
136136

137+
@CFunction(transition = Transition.NO_TRANSITION)
138+
public static native int ftruncate(int fd, SignedWord offset);
139+
140+
@CFunction(transition = Transition.NO_TRANSITION)
141+
public static native int getpid();
137142
}
138143
}

substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/linux/LinuxImageHeapProvider.java

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
import com.oracle.svm.core.c.CGlobalData;
5555
import com.oracle.svm.core.c.CGlobalDataFactory;
5656
import com.oracle.svm.core.c.function.CEntryPointErrors;
57+
import com.oracle.svm.core.code.DynamicMethodAddressResolutionHeapSupport;
5758
import com.oracle.svm.core.config.ConfigurationValues;
5859
import com.oracle.svm.core.headers.LibC;
5960
import com.oracle.svm.core.heap.Heap;
@@ -142,13 +143,22 @@ public int initialize(Pointer reservedAddressSpace, UnsignedWord reservedSize, W
142143
return fallbackCopyingProvider.initialize(reservedAddressSpace, reservedSize, basePointer, endPointer);
143144
}
144145

146+
boolean haveDynamicMethodResolution = DynamicMethodAddressResolutionHeapSupport.isEnabled();
147+
148+
if (haveDynamicMethodResolution) {
149+
int res = DynamicMethodAddressResolutionHeapSupport.get().initialize();
150+
if (res != CEntryPointErrors.NO_ERROR) {
151+
return res;
152+
}
153+
}
154+
145155
// If we are the first isolate and can use the existing image heap, do it.
146156
UnsignedWord pageSize = VirtualMemoryProvider.get().getGranularity();
147157
Word imageHeapBegin = IMAGE_HEAP_BEGIN.get();
148158
UnsignedWord imageHeapSizeInFile = getImageHeapSizeInFile();
149159
int imageHeapOffsetInAddressSpace = Heap.getHeap().getImageHeapOffsetInAddressSpace();
150160
UnsignedWord alignment = WordFactory.unsigned(Heap.getHeap().getPreferredAddressSpaceAlignment());
151-
if (firstIsolate && reservedAddressSpace.isNull() && PointerUtils.isAMultiple(imageHeapBegin, alignment) && imageHeapOffsetInAddressSpace == 0) {
161+
if (firstIsolate && reservedAddressSpace.isNull() && PointerUtils.isAMultiple(imageHeapBegin, alignment) && imageHeapOffsetInAddressSpace == 0 && !haveDynamicMethodResolution) {
152162
// Mark the whole image heap as read only.
153163
if (VirtualMemoryProvider.get().protect(imageHeapBegin, imageHeapSizeInFile, Access.READ) != 0) {
154164
return CEntryPointErrors.PROTECT_HEAP_FAILED;
@@ -176,22 +186,40 @@ public int initialize(Pointer reservedAddressSpace, UnsignedWord reservedSize, W
176186
return CEntryPointErrors.NO_ERROR;
177187
}
178188

189+
UnsignedWord preHeapRequiredBytes = WordFactory.zero();
190+
if (haveDynamicMethodResolution) {
191+
preHeapRequiredBytes = DynamicMethodAddressResolutionHeapSupport.get().getDynamicMethodAddressResolverPreHeapMemoryBytes();
192+
}
193+
179194
// Reserve an address space for the image heap if necessary.
180195
UnsignedWord imageHeapAddressSpaceSize = getImageHeapAddressSpaceSize();
196+
UnsignedWord totalAddressSpaceSize = imageHeapAddressSpaceSize.add(preHeapRequiredBytes);
197+
181198
Pointer heapBase;
182199
Pointer allocatedMemory = WordFactory.nullPointer();
183200
if (reservedAddressSpace.isNull()) {
184-
heapBase = allocatedMemory = VirtualMemoryProvider.get().reserve(imageHeapAddressSpaceSize, alignment, false);
201+
heapBase = allocatedMemory = VirtualMemoryProvider.get().reserve(totalAddressSpaceSize, alignment, false);
185202
if (allocatedMemory.isNull()) {
186203
return CEntryPointErrors.RESERVE_ADDRESS_SPACE_FAILED;
187204
}
188205
} else {
189-
if (reservedSize.belowThan(imageHeapAddressSpaceSize)) {
206+
if (reservedSize.belowThan(totalAddressSpaceSize)) {
190207
return CEntryPointErrors.INSUFFICIENT_ADDRESS_SPACE;
191208
}
192209
heapBase = reservedAddressSpace;
193210
}
194211

212+
if (haveDynamicMethodResolution) {
213+
heapBase = heapBase.add(preHeapRequiredBytes);
214+
Pointer installOffset = heapBase.subtract(DynamicMethodAddressResolutionHeapSupport.get().getRequiredPreHeapMemoryInBytes());
215+
int error = DynamicMethodAddressResolutionHeapSupport.get().install(installOffset);
216+
217+
if (error != CEntryPointErrors.NO_ERROR) {
218+
freeImageHeap(allocatedMemory);
219+
return error;
220+
}
221+
}
222+
195223
// Create memory mappings from the image file.
196224
UnsignedWord fileOffset = CACHED_IMAGE_HEAP_OFFSET.get().read();
197225
Pointer imageHeap = heapBase.add(imageHeapOffsetInAddressSpace);
@@ -343,7 +371,14 @@ public int freeImageHeap(PointerBase heapBase) {
343371
return CEntryPointErrors.MAP_HEAP_FAILED;
344372
}
345373
} else {
346-
if (VirtualMemoryProvider.get().free(heapBase, getImageHeapAddressSpaceSize()) != 0) {
374+
UnsignedWord totalAddressSpaceSize = getImageHeapAddressSpaceSize();
375+
Pointer addressSpaceStart = (Pointer) heapBase;
376+
if (DynamicMethodAddressResolutionHeapSupport.isEnabled()) {
377+
totalAddressSpaceSize = totalAddressSpaceSize.add(DynamicMethodAddressResolutionHeapSupport.get().getDynamicMethodAddressResolverPreHeapMemoryBytes());
378+
addressSpaceStart = addressSpaceStart.subtract(DynamicMethodAddressResolutionHeapSupport.get().getDynamicMethodAddressResolverPreHeapMemoryBytes());
379+
}
380+
381+
if (VirtualMemoryProvider.get().free(addressSpaceStart, totalAddressSpaceSize) != 0) {
347382
return CEntryPointErrors.MAP_HEAP_FAILED;
348383
}
349384
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/c/function/CEntryPointErrors.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,27 @@ private CEntryPointErrors() {
128128
@Description("Image page size is incompatible with run-time page size. Rebuild image with -H:PageSize=[pagesize] to set appropriately.") //
129129
public static final int PAGE_SIZE_CHECK_FAILED = 24;
130130

131+
@Description("Creating an in-memory file for the GOT failed.") //
132+
public static final int DYNAMIC_METHOD_ADDRESS_RESOLUTION_GOT_FD_CREATE_FAILED = 25;
133+
134+
@Description("Resizing the in-memory file for the GOT failed.") //
135+
public static final int DYNAMIC_METHOD_ADDRESS_RESOLUTION_GOT_FD_RESIZE_FAILED = 26;
136+
137+
@Description("Mapping and populating the in-memory file for the GOT failed.") //
138+
public static final int DYNAMIC_METHOD_ADDRESS_RESOLUTION_GOT_FD_MAP_FAILED = 27;
139+
140+
@Description("Mapping the GOT before an isolate's heap failed (no mapping).") //
141+
public static final int DYNAMIC_METHOD_ADDRESS_RESOLUTION_GOT_MMAP_FAILED = 28;
142+
143+
@Description("Mapping the GOT before an isolate's heap failed (wrong mapping).") //
144+
public static final int DYNAMIC_METHOD_ADDRESS_RESOLUTION_GOT_WRONG_MMAP = 29;
145+
146+
@Description("Mapping the GOT before an isolate's heap failed (invalid file).") //
147+
public static final int DYNAMIC_METHOD_ADDRESS_RESOLUTION_GOT_FD_INVALID = 30;
148+
149+
@Description("Could not create unique GOT file even after retrying.") //
150+
public static final int DYNAMIC_METHOD_ADDRESS_RESOLUTION_GOT_UNIQUE_FILE_CREATE_FAILED = 31;
151+
131152
public static String getDescription(int code) {
132153
String result = null;
133154
if (code >= 0 && code < DESCRIPTIONS.length) {
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/*
2+
* Copyright (c) 2022, 2022, 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. Oracle designates this
8+
* particular file as subject to the "Classpath" exception as provided
9+
* by Oracle in the LICENSE file that accompanied this code.
10+
*
11+
* This code is distributed in the hope that it will be useful, but WITHOUT
12+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+
* version 2 for more details (a copy is included in the LICENSE file that
15+
* accompanied this code).
16+
*
17+
* You should have received a copy of the GNU General Public License version
18+
* 2 along with this work; if not, write to the Free Software Foundation,
19+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+
*
21+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+
* or visit www.oracle.com if you need additional information or have any
23+
* questions.
24+
*/
25+
package com.oracle.svm.core.code;
26+
27+
import static com.oracle.svm.core.util.PointerUtils.roundUp;
28+
29+
import org.graalvm.compiler.api.replacements.Fold;
30+
import org.graalvm.nativeimage.CurrentIsolate;
31+
import org.graalvm.nativeimage.ImageSingletons;
32+
import org.graalvm.word.Pointer;
33+
import org.graalvm.word.PointerBase;
34+
import org.graalvm.word.UnsignedWord;
35+
import org.graalvm.word.WordFactory;
36+
37+
import com.oracle.svm.core.Isolates;
38+
import com.oracle.svm.core.Uninterruptible;
39+
import com.oracle.svm.core.heap.Heap;
40+
41+
public abstract class DynamicMethodAddressResolutionHeapSupport {
42+
43+
@Fold
44+
public static boolean isEnabled() {
45+
return ImageSingletons.contains(DynamicMethodAddressResolutionHeapSupport.class);
46+
}
47+
48+
@Fold
49+
public static DynamicMethodAddressResolutionHeapSupport get() {
50+
return ImageSingletons.lookup(DynamicMethodAddressResolutionHeapSupport.class);
51+
}
52+
53+
public abstract int initialize();
54+
55+
public abstract UnsignedWord getRequiredPreHeapMemoryInBytes();
56+
57+
public abstract int install(Pointer address);
58+
59+
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
60+
public UnsignedWord getDynamicMethodAddressResolverPreHeapMemoryBytes() {
61+
UnsignedWord requiredPreHeapMemoryInBytes = getRequiredPreHeapMemoryInBytes();
62+
/* Ensure there is enough space to properly align the heap */
63+
UnsignedWord heapAlignment = WordFactory.unsigned(Heap.getHeap().getPreferredAddressSpaceAlignment());
64+
return roundUp((PointerBase) requiredPreHeapMemoryInBytes, heapAlignment);
65+
}
66+
67+
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
68+
public Pointer getPreHeapMappingStartAddress() {
69+
UnsignedWord heapBase = (UnsignedWord) Isolates.getHeapBase(CurrentIsolate.getIsolate());
70+
return (Pointer) heapBase.subtract(getRequiredPreHeapMemoryInBytes());
71+
}
72+
73+
}

0 commit comments

Comments
 (0)