diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/amd64/AMD64LIRGenerator.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/amd64/AMD64LIRGenerator.java index a5e0472eca97..2f293783daf2 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/amd64/AMD64LIRGenerator.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/amd64/AMD64LIRGenerator.java @@ -978,7 +978,7 @@ public void emitBigIntegerMultiplyToLen(Value x, Value xlen, Value y, Value ylen emitMove(rZ, z); emitMove(rZlen, zlen); - append(new AMD64BigIntegerMultiplyToLenOp(rX, rXlen, rY, rYlen, rZ, rZlen, getHeapBaseRegister())); + append(new AMD64BigIntegerMultiplyToLenOp(this, rX, rXlen, rY, rYlen, rZ, rZlen)); } @Override @@ -995,7 +995,7 @@ public Variable emitBigIntegerMulAdd(Value out, Value in, Value offset, Value le emitMove(rLen, len); emitMove(rK, k); - append(new AMD64BigIntegerMulAddOp(rOut, rIn, rOffset, rLen, rK, getHeapBaseRegister())); + append(new AMD64BigIntegerMulAddOp(this, rOut, rIn, rOffset, rLen, rK)); // result of AMD64BigIntegerMulAddOp is stored at rax Variable result = newVariable(len.getValueKind()); emitMove(result, AMD64.rax.asValue(len.getValueKind())); @@ -1014,7 +1014,7 @@ public void emitBigIntegerSquareToLen(Value x, Value len, Value z, Value zlen) { emitMove(rZ, z); emitMove(rZlen, zlen); - append(new AMD64BigIntegerSquareToLenOp(rX, rLen, rZ, rZlen, getHeapBaseRegister())); + append(new AMD64BigIntegerSquareToLenOp(this, rX, rLen, rZ, rZlen)); } @Override diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/aarch64/AArch64HotSpotLIRGenerator.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/aarch64/AArch64HotSpotLIRGenerator.java index 6f6ac9175d1f..1710fbe5807a 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/aarch64/AArch64HotSpotLIRGenerator.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/aarch64/AArch64HotSpotLIRGenerator.java @@ -501,8 +501,8 @@ public int getArrayLengthOffset() { } @Override - public Register getHeapBaseRegister() { - return getProviders().getRegisters().getHeapBaseRegister(); + public boolean isReservedRegister(Register r) { + return getProviders().getRegisters().isReservedRegister(r); } @Override diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/amd64/AMD64HotSpotLIRGenerator.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/amd64/AMD64HotSpotLIRGenerator.java index 46e9d0e624c6..82eb85d49705 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/amd64/AMD64HotSpotLIRGenerator.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/amd64/AMD64HotSpotLIRGenerator.java @@ -629,8 +629,8 @@ public int getArrayLengthOffset() { } @Override - public Register getHeapBaseRegister() { - return getProviders().getRegisters().getHeapBaseRegister(); + public boolean isReservedRegister(Register r) { + return getProviders().getRegisters().isReservedRegister(r); } // no need to call super because HotSpot already overrides the value according to the CPU diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotRegisters.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotRegisters.java index ba1289be4999..1b6986fcc4a6 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotRegisters.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotRegisters.java @@ -68,4 +68,9 @@ public Register getZeroValueRegister(GraalHotSpotVMConfig config) { } return Register.None; } + + @Override + public boolean isReservedRegister(Register r) { + return !r.equals(Register.None) && (r.equals(threadRegister) || r.equals(heapBaseRegister) || r.equals(stackPointerRegister)); + } } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotRegistersProvider.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotRegistersProvider.java index 3d8066442a06..740940efb0c8 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotRegistersProvider.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotRegistersProvider.java @@ -51,4 +51,9 @@ public interface HotSpotRegistersProvider { * Gets the register whose value is always 0. */ Register getZeroValueRegister(GraalHotSpotVMConfig config); + + /** + * Determines whether the given register is one of the reserved special registers. + */ + boolean isReservedRegister(Register r); } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64BigIntegerMulAddOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64BigIntegerMulAddOp.java index 047c30a9c598..adb71a70b0c2 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64BigIntegerMulAddOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64BigIntegerMulAddOp.java @@ -50,7 +50,7 @@ import jdk.graal.compiler.lir.LIRInstructionClass; import jdk.graal.compiler.lir.SyncPort; import jdk.graal.compiler.lir.asm.CompilationResultBuilder; - +import jdk.graal.compiler.lir.gen.LIRGeneratorTool; import jdk.vm.ci.amd64.AMD64; import jdk.vm.ci.amd64.AMD64Kind; import jdk.vm.ci.code.Register; @@ -79,13 +79,15 @@ public final class AMD64BigIntegerMulAddOp extends AMD64LIRInstruction { @Temp({OperandFlag.REG}) private Value tmp1Value; @Temp({OperandFlag.REG}) private Value[] tmpValues; + private final boolean spillR13; + public AMD64BigIntegerMulAddOp( + LIRGeneratorTool tool, Value outValue, Value inValue, Value offsetValue, Value lenValue, - Value kValue, - Register heapBaseRegister) { + Value kValue) { super(TYPE); // Due to lack of allocatable registers, we use fixed registers and mark them as @Use+@Temp. @@ -103,7 +105,13 @@ public AMD64BigIntegerMulAddOp( this.kValue = kValue; this.result = AMD64.rax.asValue(lenValue.getValueKind()); - this.tmp1Value = r12.equals(heapBaseRegister) ? r14.asValue() : r12.asValue(); + if (tool.isReservedRegister(r12)) { + GraalError.guarantee(!tool.isReservedRegister(r14), "One of r12 or r14 must be available"); + this.tmp1Value = r14.asValue(); + } else { + this.tmp1Value = r12.asValue(); + } + this.spillR13 = tool.isReservedRegister(r13); this.tmpValues = new Value[]{ rax.asValue(), @@ -120,6 +128,11 @@ public AMD64BigIntegerMulAddOp( }; } + @Override + public boolean modifiesStackPointer() { + return spillR13; + } + @Override public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { GraalError.guarantee(outValue.getPlatformKind().equals(AMD64Kind.QWORD), "Invalid outValue kind: %s", outValue); @@ -140,7 +153,13 @@ public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { Register tmp4 = r10; Register tmp5 = rbx; + if (spillR13) { + masm.push(r13); + } mulAdd(masm, out, in, offset, len, k, tmp1, tmp2, tmp3, tmp4, tmp5, rdx, rax); + if (spillR13) { + masm.pop(r13); + } } static boolean useBMI2Instructions(AMD64MacroAssembler masm) { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64BigIntegerMultiplyToLenOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64BigIntegerMultiplyToLenOp.java index f80293380e9d..352f923ef1ed 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64BigIntegerMultiplyToLenOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64BigIntegerMultiplyToLenOp.java @@ -51,6 +51,7 @@ import jdk.graal.compiler.lir.LIRInstructionClass; import jdk.graal.compiler.lir.SyncPort; import jdk.graal.compiler.lir.asm.CompilationResultBuilder; +import jdk.graal.compiler.lir.gen.LIRGeneratorTool; import jdk.vm.ci.amd64.AMD64Kind; import jdk.vm.ci.code.Register; import jdk.vm.ci.meta.Value; @@ -75,14 +76,16 @@ public final class AMD64BigIntegerMultiplyToLenOp extends AMD64LIRInstruction { @Temp({OperandFlag.REG}) private Value tmp1Value; @Temp({OperandFlag.REG}) private Value[] tmpValues; + private final boolean spillR13; + public AMD64BigIntegerMultiplyToLenOp( + LIRGeneratorTool tool, Value xValue, Value xlenValue, Value yValue, Value ylenValue, Value zValue, - Value zlenValue, - Register heapBaseRegister) { + Value zlenValue) { super(TYPE); // Due to lack of allocatable registers, we use fixed registers and mark them as @Use+@Temp. @@ -101,7 +104,14 @@ public AMD64BigIntegerMultiplyToLenOp( this.zValue = zValue; this.zlenValue = zlenValue; - this.tmp1Value = r12.equals(heapBaseRegister) ? r14.asValue() : r12.asValue(); + if (tool.isReservedRegister(r12)) { + GraalError.guarantee(!tool.isReservedRegister(r14), "One of r12 or r14 must be available"); + this.tmp1Value = r14.asValue(); + } else { + this.tmp1Value = r12.asValue(); + } + this.spillR13 = tool.isReservedRegister(r13); + this.tmpValues = new Value[]{ rax.asValue(), rcx.asValue(), @@ -139,7 +149,13 @@ public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { Register tmp4 = r10; Register tmp5 = rbx; + if (spillR13) { + masm.push(r13); + } multiplyToLen(masm, x, xlen, y, ylen, z, zlen, tmp1, tmp2, tmp3, tmp4, tmp5); + if (spillR13) { + masm.pop(r13); + } } private static void add2WithCarry(AMD64MacroAssembler masm, diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64BigIntegerSquareToLenOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64BigIntegerSquareToLenOp.java index 7789c158c891..2fb7f5a68b58 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64BigIntegerSquareToLenOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64BigIntegerSquareToLenOp.java @@ -50,6 +50,7 @@ import jdk.graal.compiler.lir.LIRInstructionClass; import jdk.graal.compiler.lir.SyncPort; import jdk.graal.compiler.lir.asm.CompilationResultBuilder; +import jdk.graal.compiler.lir.gen.LIRGeneratorTool; import jdk.vm.ci.amd64.AMD64Kind; import jdk.vm.ci.code.Register; import jdk.vm.ci.meta.Value; @@ -72,12 +73,14 @@ public final class AMD64BigIntegerSquareToLenOp extends AMD64LIRInstruction { @Temp({OperandFlag.REG}) private Value tmp1Value; @Temp({OperandFlag.REG}) private Value[] tmpValues; + private final boolean spillR13; + public AMD64BigIntegerSquareToLenOp( + LIRGeneratorTool tool, Value xValue, Value lenValue, Value zValue, - Value zlenValue, - Register heapBaseRegister) { + Value zlenValue) { super(TYPE); // Due to lack of allocatable registers, we use fixed registers and mark them as @Use+@Temp. @@ -92,7 +95,14 @@ public AMD64BigIntegerSquareToLenOp( this.zValue = zValue; this.zlenValue = zlenValue; - this.tmp1Value = r12.equals(heapBaseRegister) ? r14.asValue() : r12.asValue(); + if (tool.isReservedRegister(r12)) { + GraalError.guarantee(!tool.isReservedRegister(r14), "One of r12 or r14 must be available"); + this.tmp1Value = r14.asValue(); + } else { + this.tmp1Value = r12.asValue(); + } + this.spillR13 = tool.isReservedRegister(r13); + this.tmpValues = new Value[]{ rax.asValue(), rcx.asValue(), @@ -125,7 +135,13 @@ public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { Register tmp4 = r10; Register tmp5 = rbx; + if (spillR13) { + masm.push(r13); + } squareToLen(masm, x, len, z, zlen, tmp1, tmp2, tmp3, tmp4, tmp5, rdx, rax); + if (spillR13) { + masm.pop(r13); + } } static void squareRshift(AMD64MacroAssembler masm, Register x, Register xlen, Register z, diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/gen/LIRGenerator.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/gen/LIRGenerator.java index 992f04a75d5f..af3e329ca467 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/gen/LIRGenerator.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/gen/LIRGenerator.java @@ -855,9 +855,4 @@ public LIRInstruction zapArgumentSpace() { public int getArrayBaseOffset(JavaKind elementKind) { return getMetaAccess().getArrayBaseOffset(elementKind); } - - /** - * Returns the register holding the heap base address for compressed pointer. - */ - public abstract Register getHeapBaseRegister(); } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/gen/LIRGeneratorTool.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/gen/LIRGeneratorTool.java index 4c1de320aece..ccaf4735817a 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/gen/LIRGeneratorTool.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/gen/LIRGeneratorTool.java @@ -717,4 +717,10 @@ default void emitZeroMemory(Value address, Value length, boolean isAligned) { default VectorSize getMaxVectorSize(EnumSet runtimeCheckedCPUFeatures) { throw GraalError.unimplemented("Max vector size is not specified on this architecture"); // ExcludeFromJacocoGeneratedReport } + + /** + * Determines whether the given register is a reserved register, such as the register holding + * the heap base address for compressed pointers. + */ + boolean isReservedRegister(Register r); } diff --git a/substratevm/CHANGELOG.md b/substratevm/CHANGELOG.md index fbcca64fc7d6..f56dc8607403 100644 --- a/substratevm/CHANGELOG.md +++ b/substratevm/CHANGELOG.md @@ -17,6 +17,7 @@ This changelog summarizes major changes to GraalVM Native Image. 1. `run-time-initialized-jdk` shifts away from build-time initialization of the JDK, instead initializing most of it at run time. This transition is gradual, with individual components of the JDK becoming run-time initialized in each release. This process should complete with JDK 29 when this option should not be needed anymore. Unless you store classes from the JDK in the image heap, this option should not affect you. In case this option breaks your build, follow the suggestions in the error messages. * (GR-63494) Recurring callback support is no longer enabled by default. If this feature is needed, please specify `-H:+SupportRecurringCallback` at image build-time. * (GR-60209) New syntax for configuration of the [Foreign Function & Memory API](https://github.com/oracle/graal/blob/master/docs/reference-manual/native-image/ForeignInterface.md) +* (GR-64584) Experimental option `-H:+RelativeCodePointers` to significantly reduce relocation entries in position-independent executables and shared libraries. ## GraalVM for JDK 24 (Internal Version 24.2.0) * (GR-59717) Added `DuringSetupAccess.registerObjectReachabilityHandler` to allow registering a callback that is executed when an object of a specified type is marked as reachable during heap scanning. diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/AddressRangeCommittedMemoryProvider.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/AddressRangeCommittedMemoryProvider.java index 59bcd030ba10..0a8002f1b3a6 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/AddressRangeCommittedMemoryProvider.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/AddressRangeCommittedMemoryProvider.java @@ -167,7 +167,7 @@ public int initialize(WordPointer heapBasePointer, IsolateArguments arguments) { return errorCode; } - CEntryPointSnippets.setHeapBase(heapBasePointer.read()); + CEntryPointSnippets.initBaseRegisters(heapBasePointer.read()); WordPointer runtimeHeapBeginOut = StackValue.get(WordPointer.class); errorCode = getCollectedHeapBegin(arguments, begin, reserved, imageHeapEndOut.read(), runtimeHeapBeginOut); if (errorCode != CEntryPointErrors.NO_ERROR) { diff --git a/substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/AArch64ReservedRegisters.java b/substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/AArch64ReservedRegisters.java index 52e59c4dd67e..819dbafa70ef 100755 --- a/substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/AArch64ReservedRegisters.java +++ b/substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/AArch64ReservedRegisters.java @@ -35,10 +35,11 @@ public final class AArch64ReservedRegisters extends ReservedRegisters { public static final Register THREAD_REGISTER = AArch64.r28; - public static final Register HEAP_BASE_REGISTER_CANDIDATE = AArch64.r27; + public static final Register HEAP_BASE_REGISTER = AArch64.r27; + public static final Register CODE_BASE_REGISTER_CANDIDATE = AArch64.r26; @Platforms(Platform.HOSTED_ONLY.class) AArch64ReservedRegisters() { - super(AArch64.sp, THREAD_REGISTER, HEAP_BASE_REGISTER_CANDIDATE); + super(AArch64.sp, THREAD_REGISTER, HEAP_BASE_REGISTER, CODE_BASE_REGISTER_CANDIDATE); } } diff --git a/substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/SubstrateAArch64Backend.java b/substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/SubstrateAArch64Backend.java index 351d15134171..545448c9ded3 100755 --- a/substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/SubstrateAArch64Backend.java +++ b/substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/SubstrateAArch64Backend.java @@ -678,8 +678,8 @@ public int getArrayLengthOffset() { } @Override - public Register getHeapBaseRegister() { - return ReservedRegisters.singleton().getHeapBaseRegister(); + public boolean isReservedRegister(Register r) { + return ReservedRegisters.singleton().isReservedRegister(r); } @Override diff --git a/substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/SubstrateAArch64RegisterConfig.java b/substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/SubstrateAArch64RegisterConfig.java index 678c32d75e22..58567d68de47 100755 --- a/substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/SubstrateAArch64RegisterConfig.java +++ b/substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/SubstrateAArch64RegisterConfig.java @@ -148,12 +148,10 @@ public SubstrateAArch64RegisterConfig(ConfigKind config, MetaAccessProvider meta * or sp. */ regs.remove(r31); - /* - * If enabled, the heapBaseRegister and threadRegister are r27 and r28, respectively. See - * AArch64ReservedRegisters and ReservedRegisters for more information. - */ + /* Reserved registers: see AArch64ReservedRegisters and ReservedRegisters for details. */ regs.remove(ReservedRegisters.singleton().getHeapBaseRegister()); regs.remove(ReservedRegisters.singleton().getThreadRegister()); + regs.remove(ReservedRegisters.singleton().getCodeBaseRegister()); /* * Darwin and Windows specify that r18 is a platform-reserved register: * diff --git a/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/AMD64InterpreterStubs.java b/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/AMD64InterpreterStubs.java index e14f17ea2fe1..7fbcfd719cc0 100644 --- a/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/AMD64InterpreterStubs.java +++ b/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/AMD64InterpreterStubs.java @@ -195,7 +195,7 @@ public void leave(CompilationResultBuilder crb) { /* Copy prepared outgoing args to the stack where the ABI expects it */ Register calleeSpArgs = AMD64.r12; - Register interpDataSp = AMD64.r13; + Register interpDataSp = AMD64.r9; masm.movq(interpDataSp, new AMD64Address(rax, offsetAbiSpReg())); masm.movq(calleeSpArgs, rsp); diff --git a/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/AMD64ReservedRegisters.java b/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/AMD64ReservedRegisters.java index 8e34dec2480c..86b5133de600 100644 --- a/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/AMD64ReservedRegisters.java +++ b/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/AMD64ReservedRegisters.java @@ -24,6 +24,7 @@ */ package com.oracle.svm.core.graal.amd64; +import static jdk.vm.ci.amd64.AMD64.r13; import static jdk.vm.ci.amd64.AMD64.r14; import static jdk.vm.ci.amd64.AMD64.r15; @@ -38,11 +39,12 @@ public final class AMD64ReservedRegisters extends ReservedRegisters { public static final Register THREAD_REGISTER = r15; - public static final Register HEAP_BASE_REGISTER_CANDIDATE = r14; + public static final Register HEAP_BASE_REGISTER = r14; + public static final Register CODE_BASE_REGISTER_CANDIDATE = r13; @Platforms(Platform.HOSTED_ONLY.class) AMD64ReservedRegisters() { - super(AMD64.rsp, THREAD_REGISTER, HEAP_BASE_REGISTER_CANDIDATE); + super(AMD64.rsp, THREAD_REGISTER, HEAP_BASE_REGISTER, CODE_BASE_REGISTER_CANDIDATE); } @Override diff --git a/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/SubstrateAMD64Backend.java b/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/SubstrateAMD64Backend.java index eb60f19a4185..5d2e64acbb2c 100644 --- a/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/SubstrateAMD64Backend.java +++ b/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/SubstrateAMD64Backend.java @@ -835,8 +835,8 @@ public int getArrayLengthOffset() { } @Override - public Register getHeapBaseRegister() { - return ReservedRegisters.singleton().getHeapBaseRegister(); + public boolean isReservedRegister(Register r) { + return ReservedRegisters.singleton().isReservedRegister(r); } @Override @@ -1065,7 +1065,7 @@ private AllocatableValue setupJavaFrameAnchor(CallTargetNode callTarget) { } /* Register allocator cannot handle variables at call sites, need a fixed register. */ - Register frameAnchorRegister = AMD64.r13; + Register frameAnchorRegister = AMD64.rbx; AllocatableValue frameAnchor = frameAnchorRegister.asValue(FrameAccess.getWordStamp().getLIRKind(getLIRGeneratorTool().getLIRKindTool())); gen.emitMove(frameAnchor, operand(getJavaFrameAnchor(callTarget))); return frameAnchor; diff --git a/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/SubstrateAMD64RegisterConfig.java b/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/SubstrateAMD64RegisterConfig.java index 66d1df2a37bb..271d30fdf601 100644 --- a/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/SubstrateAMD64RegisterConfig.java +++ b/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/SubstrateAMD64RegisterConfig.java @@ -160,6 +160,7 @@ public SubstrateAMD64RegisterConfig(ConfigKind config, MetaAccessProvider metaAc } regs.remove(ReservedRegisters.singleton().getHeapBaseRegister()); regs.remove(ReservedRegisters.singleton().getThreadRegister()); + regs.remove(ReservedRegisters.singleton().getCodeBaseRegister()); allocatableRegs = new RegisterArray(regs); } else { // This is the Linux 64-bit ABI for parameters. @@ -175,6 +176,7 @@ public SubstrateAMD64RegisterConfig(ConfigKind config, MetaAccessProvider metaAc } regs.remove(ReservedRegisters.singleton().getHeapBaseRegister()); regs.remove(ReservedRegisters.singleton().getThreadRegister()); + regs.remove(ReservedRegisters.singleton().getCodeBaseRegister()); allocatableRegs = new RegisterArray(regs); } diff --git a/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/LLVMGenerator.java b/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/LLVMGenerator.java index 94b05555c326..6cda1e21fec5 100644 --- a/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/LLVMGenerator.java +++ b/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/LLVMGenerator.java @@ -1850,4 +1850,9 @@ public void emitCacheWriteback(Value address) { public void emitCacheWritebackSync(boolean isPreSync) { builder.buildFence(); } + + @Override + public boolean isReservedRegister(Register r) { + return ReservedRegisters.singleton().isReservedRegister(r); + } } diff --git a/substratevm/src/com.oracle.svm.core.graal.riscv64/src/com/oracle/svm/core/graal/riscv64/RISCV64ReservedRegisters.java b/substratevm/src/com.oracle.svm.core.graal.riscv64/src/com/oracle/svm/core/graal/riscv64/RISCV64ReservedRegisters.java index 75efbba0ce86..17e59be4fa11 100644 --- a/substratevm/src/com.oracle.svm.core.graal.riscv64/src/com/oracle/svm/core/graal/riscv64/RISCV64ReservedRegisters.java +++ b/substratevm/src/com.oracle.svm.core.graal.riscv64/src/com/oracle/svm/core/graal/riscv64/RISCV64ReservedRegisters.java @@ -39,6 +39,6 @@ public final class RISCV64ReservedRegisters extends ReservedRegisters { @Platforms(Platform.HOSTED_ONLY.class) RISCV64ReservedRegisters() { - super(RISCV64.x2, THREAD_REGISTER, HEAP_BASE_REGISTER_CANDIDATE); + super(RISCV64.x2, THREAD_REGISTER, HEAP_BASE_REGISTER_CANDIDATE, null); } } diff --git a/substratevm/src/com.oracle.svm.core.graal.riscv64/src/com/oracle/svm/core/graal/riscv64/SubstrateRISCV64RegisterConfig.java b/substratevm/src/com.oracle.svm.core.graal.riscv64/src/com/oracle/svm/core/graal/riscv64/SubstrateRISCV64RegisterConfig.java index 6cdf3162df80..5f10e9821bc5 100644 --- a/substratevm/src/com.oracle.svm.core.graal.riscv64/src/com/oracle/svm/core/graal/riscv64/SubstrateRISCV64RegisterConfig.java +++ b/substratevm/src/com.oracle.svm.core.graal.riscv64/src/com/oracle/svm/core/graal/riscv64/SubstrateRISCV64RegisterConfig.java @@ -134,6 +134,7 @@ public SubstrateRISCV64RegisterConfig(ConfigKind config, MetaAccessProvider meta */ regs.remove(ReservedRegisters.singleton().getHeapBaseRegister()); regs.remove(ReservedRegisters.singleton().getThreadRegister()); + regs.remove(ReservedRegisters.singleton().getCodeBaseRegister()); regs.remove(x1); // ra regs.remove(x3); // gp allocatableRegs = new RegisterArray(regs); diff --git a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/aarch64/AArch64DarwinUContextRegisterDumper.java b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/aarch64/AArch64DarwinUContextRegisterDumper.java index f5b126432f96..ac38a5bde452 100644 --- a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/aarch64/AArch64DarwinUContextRegisterDumper.java +++ b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/aarch64/AArch64DarwinUContextRegisterDumper.java @@ -46,7 +46,7 @@ @Platforms(Platform.DARWIN_AARCH64.class) class AArch64DarwinUContextRegisterDumper implements UContextRegisterDumper { AArch64DarwinUContextRegisterDumper() { - VMError.guarantee(AArch64.r27.equals(AArch64ReservedRegisters.HEAP_BASE_REGISTER_CANDIDATE)); + VMError.guarantee(AArch64.r27.equals(AArch64ReservedRegisters.HEAP_BASE_REGISTER)); VMError.guarantee(AArch64.r28.equals(AArch64ReservedRegisters.THREAD_REGISTER)); } diff --git a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/aarch64/AArch64LinuxUContextRegisterDumper.java b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/aarch64/AArch64LinuxUContextRegisterDumper.java index 7593dd45437f..2a54be0b1102 100644 --- a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/aarch64/AArch64LinuxUContextRegisterDumper.java +++ b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/aarch64/AArch64LinuxUContextRegisterDumper.java @@ -48,7 +48,7 @@ @Platforms(Platform.LINUX_AARCH64_BASE.class) class AArch64LinuxUContextRegisterDumper implements UContextRegisterDumper { AArch64LinuxUContextRegisterDumper() { - VMError.guarantee(AArch64.r27.equals(AArch64ReservedRegisters.HEAP_BASE_REGISTER_CANDIDATE)); + VMError.guarantee(AArch64.r27.equals(AArch64ReservedRegisters.HEAP_BASE_REGISTER)); VMError.guarantee(AArch64.r28.equals(AArch64ReservedRegisters.THREAD_REGISTER)); } diff --git a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/amd64/AMD64DarwinUContextRegisterDumper.java b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/amd64/AMD64DarwinUContextRegisterDumper.java index e312245ad14e..6d202871dfc6 100644 --- a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/amd64/AMD64DarwinUContextRegisterDumper.java +++ b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/amd64/AMD64DarwinUContextRegisterDumper.java @@ -47,7 +47,7 @@ @Platforms(Platform.DARWIN_AMD64.class) class AMD64DarwinUContextRegisterDumper implements UContextRegisterDumper { AMD64DarwinUContextRegisterDumper() { - VMError.guarantee(AMD64.r14.equals(AMD64ReservedRegisters.HEAP_BASE_REGISTER_CANDIDATE)); + VMError.guarantee(AMD64.r14.equals(AMD64ReservedRegisters.HEAP_BASE_REGISTER)); VMError.guarantee(AMD64.r15.equals(AMD64ReservedRegisters.THREAD_REGISTER)); } diff --git a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/amd64/AMD64LinuxUContextRegisterDumper.java b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/amd64/AMD64LinuxUContextRegisterDumper.java index 174c48cb3467..394b0891cce2 100644 --- a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/amd64/AMD64LinuxUContextRegisterDumper.java +++ b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/amd64/AMD64LinuxUContextRegisterDumper.java @@ -48,7 +48,7 @@ @Platforms(Platform.LINUX_AMD64.class) class AMD64LinuxUContextRegisterDumper implements UContextRegisterDumper { AMD64LinuxUContextRegisterDumper() { - VMError.guarantee(AMD64.r14.equals(AMD64ReservedRegisters.HEAP_BASE_REGISTER_CANDIDATE)); + VMError.guarantee(AMD64.r14.equals(AMD64ReservedRegisters.HEAP_BASE_REGISTER)); VMError.guarantee(AMD64.r15.equals(AMD64ReservedRegisters.THREAD_REGISTER)); } diff --git a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsRegisterDumper.java b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsRegisterDumper.java index 7173eb1f66fb..02fb3c63332b 100644 --- a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsRegisterDumper.java +++ b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsRegisterDumper.java @@ -42,7 +42,7 @@ @AutomaticallyRegisteredImageSingleton(RegisterDumper.class) class WindowsRegisterDumper implements RegisterDumper { WindowsRegisterDumper() { - VMError.guarantee(AMD64.r14.equals(AMD64ReservedRegisters.HEAP_BASE_REGISTER_CANDIDATE)); + VMError.guarantee(AMD64.r14.equals(AMD64ReservedRegisters.HEAP_BASE_REGISTER)); VMError.guarantee(AMD64.r15.equals(AMD64ReservedRegisters.THREAD_REGISTER)); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/DebugHelper.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/DebugHelper.java index f41c906804ff..7906e8749f0c 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/DebugHelper.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/DebugHelper.java @@ -34,7 +34,7 @@ import org.graalvm.nativeimage.c.function.CodePointer; import org.graalvm.word.Pointer; -import com.oracle.svm.core.c.SetThreadAndHeapBasePrologue; +import com.oracle.svm.core.c.InitializeReservedRegistersPrologue; import com.oracle.svm.core.c.function.CEntryPointOptions; import com.oracle.svm.core.c.function.CEntryPointOptions.NoEpilogue; import com.oracle.svm.core.heap.Heap; @@ -63,14 +63,14 @@ public class DebugHelper { static class PointerDebugHelper { @Uninterruptible(reason = "Called with a raw pointer.") @CEntryPoint(name = "svm_dbg_ptr_isInImageHeap", include = IncludeDebugHelperMethods.class, publishAs = Publish.SymbolOnly) - @CEntryPointOptions(prologue = SetThreadAndHeapBasePrologue.class, epilogue = NoEpilogue.class) + @CEntryPointOptions(prologue = InitializeReservedRegistersPrologue.class, epilogue = NoEpilogue.class) public static boolean isInImageHeap(@SuppressWarnings("unused") IsolateThread thread, Pointer ptr) { return Heap.getHeap().isInImageHeap(ptr); } @Uninterruptible(reason = "Called with a raw pointer.") @CEntryPoint(name = "svm_dbg_ptr_isObject", include = IncludeDebugHelperMethods.class, publishAs = Publish.SymbolOnly) - @CEntryPointOptions(prologue = SetThreadAndHeapBasePrologue.class, epilogue = NoEpilogue.class) + @CEntryPointOptions(prologue = InitializeReservedRegistersPrologue.class, epilogue = NoEpilogue.class) public static boolean isObject(@SuppressWarnings("unused") IsolateThread thread, Pointer ptr) { ObjectHeader header = Heap.getHeap().getObjectHeader(); return header.pointsToObjectHeader(ptr); @@ -80,7 +80,7 @@ public static boolean isObject(@SuppressWarnings("unused") IsolateThread thread, static class HubDebugHelper { @Uninterruptible(reason = "Called with a raw object pointer.") @CEntryPoint(name = "svm_dbg_hub_getLayoutEncoding", include = IncludeDebugHelperMethods.class, publishAs = Publish.SymbolOnly) - @CEntryPointOptions(prologue = SetThreadAndHeapBasePrologue.class, epilogue = NoEpilogue.class) + @CEntryPointOptions(prologue = InitializeReservedRegistersPrologue.class, epilogue = NoEpilogue.class) public static int getLayoutEncoding(@SuppressWarnings("unused") IsolateThread thread, Pointer hubPtr) { DynamicHub hub = (DynamicHub) hubPtr.toObject(); return hub.getLayoutEncoding(); @@ -88,7 +88,7 @@ public static int getLayoutEncoding(@SuppressWarnings("unused") IsolateThread th @Uninterruptible(reason = "Called with a raw object pointer.") @CEntryPoint(name = "svm_dbg_hub_getArrayElementSize", include = IncludeDebugHelperMethods.class, publishAs = Publish.SymbolOnly) - @CEntryPointOptions(prologue = SetThreadAndHeapBasePrologue.class, epilogue = NoEpilogue.class) + @CEntryPointOptions(prologue = InitializeReservedRegistersPrologue.class, epilogue = NoEpilogue.class) public static int getArrayElementSize(@SuppressWarnings("unused") IsolateThread thread, Pointer hubPtr) { DynamicHub hub = (DynamicHub) hubPtr.toObject(); return DebugHelper.getArrayElementSize(hub); @@ -96,7 +96,7 @@ public static int getArrayElementSize(@SuppressWarnings("unused") IsolateThread @Uninterruptible(reason = "Called with a raw object pointer.") @CEntryPoint(name = "svm_dbg_hub_getArrayBaseOffset", include = IncludeDebugHelperMethods.class, publishAs = Publish.SymbolOnly) - @CEntryPointOptions(prologue = SetThreadAndHeapBasePrologue.class, epilogue = NoEpilogue.class) + @CEntryPointOptions(prologue = InitializeReservedRegistersPrologue.class, epilogue = NoEpilogue.class) public static int getArrayBaseOffset(@SuppressWarnings("unused") IsolateThread thread, Pointer hubPtr) { DynamicHub hub = (DynamicHub) hubPtr.toObject(); return DebugHelper.getArrayBaseOffset(hub); @@ -104,7 +104,7 @@ public static int getArrayBaseOffset(@SuppressWarnings("unused") IsolateThread t @Uninterruptible(reason = "Called with a raw object pointer.") @CEntryPoint(name = "svm_dbg_hub_isArray", include = IncludeDebugHelperMethods.class, publishAs = Publish.SymbolOnly) - @CEntryPointOptions(prologue = SetThreadAndHeapBasePrologue.class, epilogue = NoEpilogue.class) + @CEntryPointOptions(prologue = InitializeReservedRegistersPrologue.class, epilogue = NoEpilogue.class) public static boolean isArray(@SuppressWarnings("unused") IsolateThread thread, Pointer hubPtr) { DynamicHub hub = (DynamicHub) hubPtr.toObject(); return DebugHelper.isArray(hub); @@ -112,7 +112,7 @@ public static boolean isArray(@SuppressWarnings("unused") IsolateThread thread, @Uninterruptible(reason = "Called with a raw object pointer.") @CEntryPoint(name = "svm_dbg_hub_isPrimitiveArray", include = IncludeDebugHelperMethods.class, publishAs = Publish.SymbolOnly) - @CEntryPointOptions(prologue = SetThreadAndHeapBasePrologue.class, epilogue = NoEpilogue.class) + @CEntryPointOptions(prologue = InitializeReservedRegistersPrologue.class, epilogue = NoEpilogue.class) public static boolean isPrimitiveArray(@SuppressWarnings("unused") IsolateThread thread, Pointer hubPtr) { DynamicHub hub = (DynamicHub) hubPtr.toObject(); return DebugHelper.isPrimitiveArray(hub); @@ -120,7 +120,7 @@ public static boolean isPrimitiveArray(@SuppressWarnings("unused") IsolateThread @Uninterruptible(reason = "Called with a raw object pointer.") @CEntryPoint(name = "svm_dbg_hub_isObjectArray", include = IncludeDebugHelperMethods.class, publishAs = Publish.SymbolOnly) - @CEntryPointOptions(prologue = SetThreadAndHeapBasePrologue.class, epilogue = NoEpilogue.class) + @CEntryPointOptions(prologue = InitializeReservedRegistersPrologue.class, epilogue = NoEpilogue.class) public static boolean isObjectArray(@SuppressWarnings("unused") IsolateThread thread, Pointer hubPtr) { DynamicHub hub = (DynamicHub) hubPtr.toObject(); return DebugHelper.isObjectArray(hub); @@ -128,7 +128,7 @@ public static boolean isObjectArray(@SuppressWarnings("unused") IsolateThread th @Uninterruptible(reason = "Called with a raw object pointer.") @CEntryPoint(name = "svm_dbg_hub_isInstance", include = IncludeDebugHelperMethods.class, publishAs = Publish.SymbolOnly) - @CEntryPointOptions(prologue = SetThreadAndHeapBasePrologue.class, epilogue = NoEpilogue.class) + @CEntryPointOptions(prologue = InitializeReservedRegistersPrologue.class, epilogue = NoEpilogue.class) public static boolean isInstance(@SuppressWarnings("unused") IsolateThread thread, Pointer hubPtr) { DynamicHub hub = (DynamicHub) hubPtr.toObject(); return DebugHelper.isInstance(hub); @@ -136,7 +136,7 @@ public static boolean isInstance(@SuppressWarnings("unused") IsolateThread threa @Uninterruptible(reason = "Called with a raw object pointer.") @CEntryPoint(name = "svm_dbg_hub_isReference", include = IncludeDebugHelperMethods.class, publishAs = Publish.SymbolOnly) - @CEntryPointOptions(prologue = SetThreadAndHeapBasePrologue.class, epilogue = NoEpilogue.class) + @CEntryPointOptions(prologue = InitializeReservedRegistersPrologue.class, epilogue = NoEpilogue.class) public static boolean isReference(@SuppressWarnings("unused") IsolateThread thread, Pointer hubPtr) { DynamicHub hub = (DynamicHub) hubPtr.toObject(); return DebugHelper.isReference(hub); @@ -146,7 +146,7 @@ public static boolean isReference(@SuppressWarnings("unused") IsolateThread thre static class ObjectDebugHelper { @Uninterruptible(reason = "Called with a raw object pointer.") @CEntryPoint(name = "svm_dbg_obj_getHub", include = IncludeDebugHelperMethods.class, publishAs = Publish.SymbolOnly) - @CEntryPointOptions(prologue = SetThreadAndHeapBasePrologue.class, epilogue = NoEpilogue.class) + @CEntryPointOptions(prologue = InitializeReservedRegistersPrologue.class, epilogue = NoEpilogue.class) public static long getHub(@SuppressWarnings("unused") IsolateThread thread, Pointer objPtr) { Object obj = objPtr.toObject(); return Word.objectToUntrackedPointer(KnownIntrinsics.readHub(obj)).rawValue(); @@ -154,7 +154,7 @@ public static long getHub(@SuppressWarnings("unused") IsolateThread thread, Poin @Uninterruptible(reason = "Called with a raw object pointer.") @CEntryPoint(name = "svm_dbg_obj_getObjectSize", include = IncludeDebugHelperMethods.class, publishAs = Publish.SymbolOnly) - @CEntryPointOptions(prologue = SetThreadAndHeapBasePrologue.class, epilogue = NoEpilogue.class) + @CEntryPointOptions(prologue = InitializeReservedRegistersPrologue.class, epilogue = NoEpilogue.class) public static long getObjectSize(@SuppressWarnings("unused") IsolateThread thread, Pointer objPtr) { Object obj = objPtr.toObject(); return LayoutEncoding.getSizeFromObject(obj).rawValue(); @@ -162,7 +162,7 @@ public static long getObjectSize(@SuppressWarnings("unused") IsolateThread threa @Uninterruptible(reason = "Called with a raw object pointer.") @CEntryPoint(name = "svm_dbg_obj_getArrayElementSize", include = IncludeDebugHelperMethods.class, publishAs = Publish.SymbolOnly) - @CEntryPointOptions(prologue = SetThreadAndHeapBasePrologue.class, epilogue = NoEpilogue.class) + @CEntryPointOptions(prologue = InitializeReservedRegistersPrologue.class, epilogue = NoEpilogue.class) public static int getArrayElementSize(@SuppressWarnings("unused") IsolateThread thread, Pointer objPtr) { Object obj = objPtr.toObject(); DynamicHub hub = KnownIntrinsics.readHub(obj); @@ -171,7 +171,7 @@ public static int getArrayElementSize(@SuppressWarnings("unused") IsolateThread @Uninterruptible(reason = "Called with a raw object pointer.") @CEntryPoint(name = "svm_dbg_obj_getArrayBaseOffset", include = IncludeDebugHelperMethods.class, publishAs = Publish.SymbolOnly) - @CEntryPointOptions(prologue = SetThreadAndHeapBasePrologue.class, epilogue = NoEpilogue.class) + @CEntryPointOptions(prologue = InitializeReservedRegistersPrologue.class, epilogue = NoEpilogue.class) public static long getArrayBaseOffset(@SuppressWarnings("unused") IsolateThread thread, Pointer objPtr) { Object obj = objPtr.toObject(); DynamicHub hub = KnownIntrinsics.readHub(obj); @@ -180,7 +180,7 @@ public static long getArrayBaseOffset(@SuppressWarnings("unused") IsolateThread @Uninterruptible(reason = "Called with a raw object pointer.") @CEntryPoint(name = "svm_dbg_obj_isArray", include = IncludeDebugHelperMethods.class, publishAs = Publish.SymbolOnly) - @CEntryPointOptions(prologue = SetThreadAndHeapBasePrologue.class, epilogue = NoEpilogue.class) + @CEntryPointOptions(prologue = InitializeReservedRegistersPrologue.class, epilogue = NoEpilogue.class) public static boolean isArray(@SuppressWarnings("unused") IsolateThread thread, Pointer objPtr) { Object obj = objPtr.toObject(); DynamicHub hub = KnownIntrinsics.readHub(obj); @@ -189,7 +189,7 @@ public static boolean isArray(@SuppressWarnings("unused") IsolateThread thread, @Uninterruptible(reason = "Called with a raw object pointer.") @CEntryPoint(name = "svm_dbg_obj_isPrimitiveArray", include = IncludeDebugHelperMethods.class, publishAs = Publish.SymbolOnly) - @CEntryPointOptions(prologue = SetThreadAndHeapBasePrologue.class, epilogue = NoEpilogue.class) + @CEntryPointOptions(prologue = InitializeReservedRegistersPrologue.class, epilogue = NoEpilogue.class) public static boolean isPrimitiveArray(@SuppressWarnings("unused") IsolateThread thread, Pointer objPtr) { Object obj = objPtr.toObject(); DynamicHub hub = KnownIntrinsics.readHub(obj); @@ -198,7 +198,7 @@ public static boolean isPrimitiveArray(@SuppressWarnings("unused") IsolateThread @Uninterruptible(reason = "Called with a raw object pointer.") @CEntryPoint(name = "svm_dbg_obj_isObjectArray", include = IncludeDebugHelperMethods.class, publishAs = Publish.SymbolOnly) - @CEntryPointOptions(prologue = SetThreadAndHeapBasePrologue.class, epilogue = NoEpilogue.class) + @CEntryPointOptions(prologue = InitializeReservedRegistersPrologue.class, epilogue = NoEpilogue.class) public static boolean isObjectArray(@SuppressWarnings("unused") IsolateThread thread, Pointer objPtr) { Object obj = objPtr.toObject(); DynamicHub hub = KnownIntrinsics.readHub(obj); @@ -207,7 +207,7 @@ public static boolean isObjectArray(@SuppressWarnings("unused") IsolateThread th @Uninterruptible(reason = "Called with a raw object pointer.") @CEntryPoint(name = "svm_dbg_obj_isInstance", include = IncludeDebugHelperMethods.class, publishAs = Publish.SymbolOnly) - @CEntryPointOptions(prologue = SetThreadAndHeapBasePrologue.class, epilogue = NoEpilogue.class) + @CEntryPointOptions(prologue = InitializeReservedRegistersPrologue.class, epilogue = NoEpilogue.class) public static boolean isInstance(@SuppressWarnings("unused") IsolateThread thread, Pointer objPtr) { Object obj = objPtr.toObject(); DynamicHub hub = KnownIntrinsics.readHub(obj); @@ -216,7 +216,7 @@ public static boolean isInstance(@SuppressWarnings("unused") IsolateThread threa @Uninterruptible(reason = "Called with a raw object pointer.") @CEntryPoint(name = "svm_dbg_obj_isReference", include = IncludeDebugHelperMethods.class, publishAs = Publish.SymbolOnly) - @CEntryPointOptions(prologue = SetThreadAndHeapBasePrologue.class, epilogue = NoEpilogue.class) + @CEntryPointOptions(prologue = InitializeReservedRegistersPrologue.class, epilogue = NoEpilogue.class) public static boolean isReference(@SuppressWarnings("unused") IsolateThread thread, Pointer objPtr) { Object obj = objPtr.toObject(); DynamicHub hub = KnownIntrinsics.readHub(obj); @@ -225,14 +225,14 @@ public static boolean isReference(@SuppressWarnings("unused") IsolateThread thre @Uninterruptible(reason = "Called with a raw object pointer.") @CEntryPoint(name = "svm_dbg_obj_uncompress", include = IncludeDebugHelperMethods.class, publishAs = Publish.SymbolOnly) - @CEntryPointOptions(prologue = SetThreadAndHeapBasePrologue.class, epilogue = NoEpilogue.class) + @CEntryPointOptions(prologue = InitializeReservedRegistersPrologue.class, epilogue = NoEpilogue.class) public static long uncompressObjectPointer(@SuppressWarnings("unused") IsolateThread thread, Pointer compressedPtr) { return Word.objectToUntrackedPointer(ReferenceAccess.singleton().uncompressReference(compressedPtr)).rawValue(); } @Uninterruptible(reason = "Called with a raw object pointer.") @CEntryPoint(name = "svm_dbg_obj_compress", include = IncludeDebugHelperMethods.class, publishAs = Publish.SymbolOnly) - @CEntryPointOptions(prologue = SetThreadAndHeapBasePrologue.class, epilogue = NoEpilogue.class) + @CEntryPointOptions(prologue = InitializeReservedRegistersPrologue.class, epilogue = NoEpilogue.class) public static long compressObjectPointer(@SuppressWarnings("unused") IsolateThread thread, Pointer objPtr) { Object obj = objPtr.toObject(); return ReferenceAccess.singleton().getCompressedRepresentation(obj).rawValue(); @@ -242,7 +242,7 @@ public static long compressObjectPointer(@SuppressWarnings("unused") IsolateThre static class StringDebugHelper { @Uninterruptible(reason = "Called with a raw object pointer.") @CEntryPoint(name = "svm_dbg_string_length", include = IncludeDebugHelperMethods.class, publishAs = Publish.SymbolOnly) - @CEntryPointOptions(prologue = SetThreadAndHeapBasePrologue.class, epilogue = NoEpilogue.class) + @CEntryPointOptions(prologue = InitializeReservedRegistersPrologue.class, epilogue = NoEpilogue.class) public static int getStringLength(@SuppressWarnings("unused") IsolateThread thread, Pointer strPtr) { String str = (String) strPtr.toObject(); return str.length(); @@ -252,7 +252,7 @@ public static int getStringLength(@SuppressWarnings("unused") IsolateThread thre static class DiagnosticDebugHelper { @Uninterruptible(reason = "Called with a raw object pointer.", calleeMustBe = false) @CEntryPoint(name = "svm_dbg_print_hub", include = IncludeDebugHelperMethods.class, publishAs = Publish.SymbolOnly) - @CEntryPointOptions(prologue = SetThreadAndHeapBasePrologue.class, epilogue = NoEpilogue.class) + @CEntryPointOptions(prologue = InitializeReservedRegistersPrologue.class, epilogue = NoEpilogue.class) public static void printHub(@SuppressWarnings("unused") IsolateThread thread, Pointer hubPtr) { DynamicHub hub = (DynamicHub) hubPtr.toObject(); Log.log().string(hub.getName()).newline(); @@ -260,7 +260,7 @@ public static void printHub(@SuppressWarnings("unused") IsolateThread thread, Po @Uninterruptible(reason = "Called with a raw object pointer.", calleeMustBe = false) @CEntryPoint(name = "svm_dbg_print_obj", include = IncludeDebugHelperMethods.class, publishAs = Publish.SymbolOnly) - @CEntryPointOptions(prologue = SetThreadAndHeapBasePrologue.class, epilogue = NoEpilogue.class) + @CEntryPointOptions(prologue = InitializeReservedRegistersPrologue.class, epilogue = NoEpilogue.class) public static void printObject(@SuppressWarnings("unused") IsolateThread thread, Pointer objPtr) { SubstrateDiagnostics.printObjectInfo(Log.log(), objPtr.toObject()); Log.log().newline(); @@ -268,7 +268,7 @@ public static void printObject(@SuppressWarnings("unused") IsolateThread thread, @Uninterruptible(reason = "Called with a raw object pointer.", calleeMustBe = false) @CEntryPoint(name = "svm_dbg_print_string", include = IncludeDebugHelperMethods.class, publishAs = Publish.SymbolOnly) - @CEntryPointOptions(prologue = SetThreadAndHeapBasePrologue.class, epilogue = NoEpilogue.class) + @CEntryPointOptions(prologue = InitializeReservedRegistersPrologue.class, epilogue = NoEpilogue.class) public static void printString(@SuppressWarnings("unused") IsolateThread thread, Pointer strPtr) { String str = (String) strPtr.toObject(); Log.log().string(str).newline(); @@ -276,14 +276,14 @@ public static void printString(@SuppressWarnings("unused") IsolateThread thread, @Uninterruptible(reason = "Just to keep the verification happy.", calleeMustBe = false) @CEntryPoint(name = "svm_dbg_print_fatalErrorDiagnostics", include = IncludeDebugHelperMethods.class, publishAs = Publish.SymbolOnly) - @CEntryPointOptions(prologue = SetThreadAndHeapBasePrologue.class, epilogue = NoEpilogue.class) + @CEntryPointOptions(prologue = InitializeReservedRegistersPrologue.class, epilogue = NoEpilogue.class) public static void printFatalErrorDiagnostics(@SuppressWarnings("unused") IsolateThread thread, Pointer sp, CodePointer ip) { SubstrateDiagnostics.printFatalError(Log.log(), sp, ip, Word.nullPointer(), false); } @Uninterruptible(reason = "Just to keep the verification happy.", calleeMustBe = false) @CEntryPoint(name = "svm_dbg_print_locationInfo", include = IncludeDebugHelperMethods.class, publishAs = Publish.SymbolOnly) - @CEntryPointOptions(prologue = SetThreadAndHeapBasePrologue.class, epilogue = NoEpilogue.class) + @CEntryPointOptions(prologue = InitializeReservedRegistersPrologue.class, epilogue = NoEpilogue.class) public static void printLocationInfo(@SuppressWarnings("unused") IsolateThread thread, Pointer mem) { SubstrateDiagnostics.printLocationInfo(Log.log(), mem, true, true); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/ReservedRegisters.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/ReservedRegisters.java index 1b2595dbbe18..c962db6dcecf 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/ReservedRegisters.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/ReservedRegisters.java @@ -45,12 +45,14 @@ public static ReservedRegisters singleton() { protected final Register frameRegister; protected final Register threadRegister; protected final Register heapBaseRegister; + protected final Register codeBaseRegister; @Platforms(Platform.HOSTED_ONLY.class) - protected ReservedRegisters(Register frameRegister, Register threadRegister, Register heapBaseRegister) { + protected ReservedRegisters(Register frameRegister, Register threadRegister, Register heapBaseRegister, Register codeBaseRegisterCandidate) { this.frameRegister = frameRegister; this.threadRegister = threadRegister; this.heapBaseRegister = heapBaseRegister; + this.codeBaseRegister = SubstrateOptions.useRelativeCodePointers() ? codeBaseRegisterCandidate : null; } /** @@ -76,22 +78,28 @@ public Register getHeapBaseRegister() { return heapBaseRegister; } + /** + * Returns the register holding the code base address for method pointers, or {@code null} if no + * code base register is used. + */ + public Register getCodeBaseRegister() { + return codeBaseRegister; + } + /** * Returns true if the provided value is a {@link RegisterValue} for a reserved register that is * allowed to be in a frame state, i.e., for a reserved register that can be handled by * deoptimization. */ public boolean isAllowedInFrameState(JavaValue value) { - if (value instanceof RegisterValue) { - Register register = ((RegisterValue) value).getRegister(); - if (register.equals(threadRegister) || register.equals(heapBaseRegister)) { - return true; - } + if (value instanceof RegisterValue rv) { + Register r = rv.getRegister(); + return r.equals(threadRegister) || r.equals(heapBaseRegister) || r.equals(codeBaseRegister); } return false; } - public boolean isReservedRegister(Register reg) { - return reg.equals(this.frameRegister) || reg.equals(this.heapBaseRegister) || reg.equals(this.threadRegister); + public boolean isReservedRegister(Register r) { + return r.equals(frameRegister) || r.equals(heapBaseRegister) || r.equals(threadRegister) || r.equals(codeBaseRegister); } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java index e753d57511f3..2f912ff5f7e9 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java @@ -891,6 +891,9 @@ public void printDiagnostics(Log log, ErrorContext context, int maxDiagnosticLev log.string("Runtime information:").indent(true); log.string("Isolate id: ").signed(Isolates.getIsolateId()).newline(); log.string("Heap base: ").zhex(KnownIntrinsics.heapBase()).newline(); + if (SubstrateOptions.RelativeCodePointers.getValue()) { + log.string("Code base: ").zhex(KnownIntrinsics.codeBase()).newline(); + } log.string("CGlobalData base: ").zhex(CGlobalDataInfo.CGLOBALDATA_RUNTIME_BASE_ADDRESS.getPointer()).newline(); if (Container.singleton().isContainerized()) { @@ -1142,6 +1145,11 @@ private static final class ImageCodeLocationInfoPrinter { * NOTE: this method may only be called by a single thread. */ public boolean printLocationInfo(Log log, UnsignedWord value) { + if (SubstrateOptions.RelativeCodePointers.getValue() && KnownIntrinsics.codeBase().equal(value)) { + log.string("is the code base"); + return true; + } + CodeInfo imageCodeInfo = CodeInfoTable.getFirstImageCodeInfo(); while (imageCodeInfo.isNonNull()) { if (imageCodeInfo.equal(value)) { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java index 5f2dff7adf90..1a97ff57bff9 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java @@ -31,6 +31,8 @@ import static jdk.graal.compiler.core.common.SpectrePHTMitigations.Options.SpectrePHTBarriers; import static jdk.graal.compiler.options.OptionType.Expert; import static jdk.graal.compiler.options.OptionType.User; +import static org.graalvm.nativeimage.impl.InternalPlatform.NATIVE_ONLY; +import static org.graalvm.nativeimage.impl.InternalPlatform.PLATFORM_JNI; import java.nio.file.InvalidPathException; import java.nio.file.Path; @@ -50,6 +52,7 @@ import com.oracle.svm.core.c.libc.MuslLibC; import com.oracle.svm.core.config.ConfigurationValues; import com.oracle.svm.core.heap.ReferenceHandler; +import com.oracle.svm.core.imagelayer.ImageLayerBuildingSupport; import com.oracle.svm.core.option.APIOption; import com.oracle.svm.core.option.APIOptionGroup; import com.oracle.svm.core.option.AccumulatingLocatableMultiOptionValue; @@ -62,6 +65,7 @@ import com.oracle.svm.core.option.ReplacingLocatableMultiOptionValue; import com.oracle.svm.core.option.RuntimeOptionKey; import com.oracle.svm.core.option.SubstrateOptionsParser; +import com.oracle.svm.core.pltgot.PLTGOTConfiguration; import com.oracle.svm.core.thread.VMOperationControl; import com.oracle.svm.core.util.UserError; import com.oracle.svm.core.util.VMError; @@ -1435,4 +1439,36 @@ public static boolean printClosedArenaUponThrow() { return PrintClosedArenaUponThrow.getValue(); } + @Option(help = "Avoid linker relocations for code and instead emit address computations.", type = OptionType.Expert) // + public static final HostedOptionKey RelativeCodePointers = new HostedOptionKey<>(false, SubstrateOptions::validateRelativeCodePointers); + + @Fold + public static boolean useRelativeCodePointers() { + return RelativeCodePointers.getValue(); + } + + private static void validateRelativeCodePointers(HostedOptionKey optionKey) { + if (optionKey.getValue()) { + String enabledOption = SubstrateOptionsParser.commandArgument(optionKey, "+"); + + UserError.guarantee(Platform.includedIn(PLATFORM_JNI.class) || Platform.includedIn(NATIVE_ONLY.class), "%s is supported only with hardware target platforms.", enabledOption); + + /* + * GR-59707: Dispatch tables must potentially be patched at runtime still. Method + * offsets for dispatch need to be passed on between layer builds rather than using + * symbol names. + */ + UserError.guarantee(!ImageLayerBuildingSupport.buildingImageLayer(), "%s is currently not supported with layered images.", enabledOption); + + // The concept of a code base would need to be introduced in the LLVM backend first. + UserError.guarantee(!useLLVMBackend(), "%s is currently not supported with the LLVM backend.", enabledOption); + + /* + * Code offsets of PLT stubs cannot be predetermined because the PLT is separate from + * the text section and has its own base address. It would need to become a part of the + * text section (e.g., by turning it into a compilation unit). + */ + UserError.guarantee(!PLTGOTConfiguration.isEnabled(), "%s cannot be used together with PLT/GOT.", enabledOption); + } + } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateSegfaultHandler.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateSegfaultHandler.java index 42c6589ae566..904a95de76fd 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateSegfaultHandler.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateSegfaultHandler.java @@ -188,7 +188,7 @@ private static boolean tryEnterIsolateViaThreadRegister(RegisterDumper.Context c if (isolateThread.isNonNull()) { Isolate isolate = VMThreads.IsolateTL.get(isolateThread); if (isValid(isolate)) { - CEntryPointSnippets.setHeapBase(isolate); + CEntryPointSnippets.initBaseRegisters(isolate); WriteCurrentVMThreadNode.writeCurrentVMThread(isolateThread); return true; } @@ -200,10 +200,10 @@ private static boolean tryEnterIsolateViaThreadRegister(RegisterDumper.Context c @NeverInline("Prevent register writes from floating") private static boolean tryEnterIsolateViaHeapBaseRegister(RegisterDumper.Context context) { /* - * Set the heap base register to null so that we don't execute this code more than once if - * we trigger a recursive segfault. + * Set the base registers to null so that we don't execute this code more than once if we + * trigger a recursive segfault. */ - CEntryPointSnippets.setHeapBase(Word.nullPointer()); + CEntryPointSnippets.initBaseRegisters(Word.nullPointer(), Word.nullPointer()); Isolate isolate = (Isolate) RegisterDumper.singleton().getHeapBase(context); if (isValid(isolate)) { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/c/InitializeReservedRegistersPrologue.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/c/InitializeReservedRegistersPrologue.java new file mode 100644 index 000000000000..f4f16f7ac406 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/c/InitializeReservedRegistersPrologue.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2023, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.core.c; + +import org.graalvm.nativeimage.IsolateThread; + +import com.oracle.svm.core.ReservedRegisters; +import com.oracle.svm.core.Uninterruptible; +import com.oracle.svm.core.c.function.CEntryPointOptions; +import com.oracle.svm.core.graal.nodes.WriteCurrentVMThreadNode; +import com.oracle.svm.core.graal.snippets.CEntryPointSnippets; +import com.oracle.svm.core.thread.VMThreads; + +/** + * Only sets the {@linkplain ReservedRegisters reserved registers}, but does not do any thread + * transitions. Only use this prologue if + * {@link com.oracle.svm.core.c.function.CEntryPointSetup.EnterPrologue} can't be used. + */ +public class InitializeReservedRegistersPrologue implements CEntryPointOptions.Prologue { + @Uninterruptible(reason = "prologue") + public static void enter(IsolateThread thread) { + WriteCurrentVMThreadNode.writeCurrentVMThread(thread); + CEntryPointSnippets.initBaseRegisters(VMThreads.IsolateTL.get()); + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/c/SetThreadAndHeapBasePrologue.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/c/SetThreadAndHeapBasePrologue.java index c1ecb42288ac..781e644c412f 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/c/SetThreadAndHeapBasePrologue.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/c/SetThreadAndHeapBasePrologue.java @@ -28,19 +28,13 @@ import com.oracle.svm.core.Uninterruptible; import com.oracle.svm.core.c.function.CEntryPointOptions; -import com.oracle.svm.core.graal.nodes.WriteCurrentVMThreadNode; -import com.oracle.svm.core.graal.snippets.CEntryPointSnippets; -import com.oracle.svm.core.thread.VMThreads; /** - * Only sets the heap base and the thread register but does not do any thread transitions. Only use - * this prologue if {@link com.oracle.svm.core.c.function.CEntryPointSetup.EnterPrologue} can't be - * used. + * GR-64740: required by legacy code. Use {@link InitializeReservedRegistersPrologue} instead. */ public class SetThreadAndHeapBasePrologue implements CEntryPointOptions.Prologue { @Uninterruptible(reason = "prologue") public static void enter(IsolateThread thread) { - WriteCurrentVMThreadNode.writeCurrentVMThread(thread); - CEntryPointSnippets.setHeapBase(VMThreads.IsolateTL.get()); + InitializeReservedRegistersPrologue.enter(thread); } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/deopt/DeoptState.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/deopt/DeoptState.java index a14d47322378..1ab5f77be1ab 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/deopt/DeoptState.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/deopt/DeoptState.java @@ -34,6 +34,7 @@ import org.graalvm.word.Pointer; import org.graalvm.word.SignedWord; import org.graalvm.word.UnsignedWord; +import org.graalvm.word.WordBase; import com.oracle.svm.core.ReservedRegisters; import com.oracle.svm.core.code.FrameInfoQueryResult; @@ -43,12 +44,15 @@ import com.oracle.svm.core.hub.DynamicHub; import com.oracle.svm.core.hub.LayoutEncoding; import com.oracle.svm.core.meta.SubstrateObjectConstant; +import com.oracle.svm.core.snippets.KnownIntrinsics; import jdk.graal.compiler.core.common.util.TypeConversion; import jdk.graal.compiler.word.Word; import jdk.internal.misc.Unsafe; +import jdk.vm.ci.code.Register; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.PrimitiveConstant; public class DeoptState { @@ -98,10 +102,17 @@ protected JavaConstant readValue(FrameInfoQueryResult.ValueInfo valueInfo, Frame case Register: return readConstant(sourceSp, Word.signed(valueInfo.getData()), valueInfo.getKind(), valueInfo.isCompressedReference(), sourceFrame); case ReservedRegister: - if (ReservedRegisters.singleton().getThreadRegister() != null && ReservedRegisters.singleton().getThreadRegister().number == valueInfo.getData()) { - return JavaConstant.forIntegerKind(ConfigurationValues.getWordKind(), targetThread.rawValue()); - } else if (ReservedRegisters.singleton().getHeapBaseRegister() != null && ReservedRegisters.singleton().getHeapBaseRegister().number == valueInfo.getData()) { - return JavaConstant.forIntegerKind(ConfigurationValues.getWordKind(), CurrentIsolate.getIsolate().rawValue()); + ReservedRegisters regs = ReservedRegisters.singleton(); + + if (refersToRegister(valueInfo, regs.getThreadRegister())) { + return createWordConstant(targetThread); + + } else if (refersToRegister(valueInfo, regs.getHeapBaseRegister())) { + return createWordConstant(CurrentIsolate.getIsolate()); + + } else if (refersToRegister(valueInfo, regs.getCodeBaseRegister())) { + return createWordConstant(KnownIntrinsics.codeBase()); + } else { throw fatalDeoptimizationError("Unexpected reserved register: " + valueInfo.getData(), sourceFrame); } @@ -116,6 +127,14 @@ protected JavaConstant readValue(FrameInfoQueryResult.ValueInfo valueInfo, Frame } } + private static boolean refersToRegister(FrameInfoQueryResult.ValueInfo valueInfo, Register register) { + return register != null && valueInfo.getData() == register.number; + } + + private static PrimitiveConstant createWordConstant(WordBase word) { + return JavaConstant.forIntegerKind(ConfigurationValues.getWordKind(), word.rawValue()); + } + /** * Materializes a virtual object. * diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/SubstrateBasicLoweringProvider.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/SubstrateBasicLoweringProvider.java index 5d216e1f0759..518ef3771296 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/SubstrateBasicLoweringProvider.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/SubstrateBasicLoweringProvider.java @@ -31,12 +31,9 @@ import org.graalvm.nativeimage.Platforms; import com.oracle.svm.core.StaticFieldsSupport; -import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.config.ConfigurationValues; import com.oracle.svm.core.config.ObjectLayout; -import com.oracle.svm.core.graal.code.SubstrateBackend; import com.oracle.svm.core.graal.nodes.FloatingWordCastNode; -import com.oracle.svm.core.graal.nodes.LoadOpenTypeWorldDispatchTableStartingOffset; import com.oracle.svm.core.graal.nodes.LoweredDeadEndNode; import com.oracle.svm.core.graal.nodes.SubstrateCompressionNode; import com.oracle.svm.core.graal.nodes.SubstrateFieldLocationIdentity; @@ -48,11 +45,9 @@ import com.oracle.svm.core.hub.DynamicHub; import com.oracle.svm.core.identityhashcode.IdentityHashCodeSupport; import com.oracle.svm.core.meta.SharedField; -import com.oracle.svm.core.meta.SharedMethod; import com.oracle.svm.core.snippets.SubstrateIsArraySnippets; import jdk.graal.compiler.core.common.memory.BarrierType; -import jdk.graal.compiler.core.common.memory.MemoryOrderMode; import jdk.graal.compiler.core.common.spi.ForeignCallsProvider; import jdk.graal.compiler.core.common.spi.MetaAccessExtensionProvider; import jdk.graal.compiler.core.common.type.AbstractObjectStamp; @@ -68,21 +63,17 @@ import jdk.graal.compiler.nodes.DeadEndNode; import jdk.graal.compiler.nodes.FieldLocationIdentity; import jdk.graal.compiler.nodes.FixedNode; -import jdk.graal.compiler.nodes.FixedWithNextNode; import jdk.graal.compiler.nodes.NamedLocationIdentity; import jdk.graal.compiler.nodes.NodeView; import jdk.graal.compiler.nodes.StructuredGraph; import jdk.graal.compiler.nodes.ValueNode; -import jdk.graal.compiler.nodes.calc.AddNode; import jdk.graal.compiler.nodes.calc.AndNode; import jdk.graal.compiler.nodes.calc.LeftShiftNode; import jdk.graal.compiler.nodes.calc.NarrowNode; import jdk.graal.compiler.nodes.calc.UnsignedRightShiftNode; import jdk.graal.compiler.nodes.calc.ZeroExtendNode; import jdk.graal.compiler.nodes.extended.LoadHubNode; -import jdk.graal.compiler.nodes.extended.LoadMethodNode; import jdk.graal.compiler.nodes.memory.FloatingReadNode; -import jdk.graal.compiler.nodes.memory.ReadNode; import jdk.graal.compiler.nodes.memory.address.AddressNode; import jdk.graal.compiler.nodes.memory.address.OffsetAddressNode; import jdk.graal.compiler.nodes.spi.LoweringTool; @@ -105,7 +96,6 @@ public abstract class SubstrateBasicLoweringProvider extends DefaultJavaLowering private final Map, NodeLoweringProvider> lowerings; private RuntimeConfiguration runtimeConfig; - private final KnownOffsets knownOffsets; private final DynamicHubOffsets dynamicHubOffsets; private final AbstractObjectStamp hubStamp; @@ -121,7 +111,6 @@ public SubstrateBasicLoweringProvider(MetaAccessProvider metaAccess, ForeignCall hubRefStamp = SubstrateNarrowOopStamp.compressed(hubRefStamp, ReferenceAccess.singleton().getCompressEncoding()); } hubStamp = hubRefStamp; - knownOffsets = KnownOffsets.singleton(); dynamicHubOffsets = DynamicHubOffsets.singleton(); } @@ -156,54 +145,11 @@ public void lower(Node n, LoweringTool tool) { lowerAssertionNode((AssertionNode) n); } else if (n instanceof DeadEndNode) { lowerDeadEnd((DeadEndNode) n); - } else if (n instanceof LoadMethodNode) { - lowerLoadMethodNode((LoadMethodNode) n, tool); } else { super.lower(n, tool); } } - private void lowerLoadMethodNode(LoadMethodNode loadMethodNode, LoweringTool tool) { - StructuredGraph graph = loadMethodNode.graph(); - SharedMethod method = (SharedMethod) loadMethodNode.getMethod(); - ValueNode hub = loadMethodNode.getHub(); - - if (SubstrateOptions.useClosedTypeWorldHubLayout()) { - - int vtableEntryOffset = knownOffsets.getVTableOffset(method.getVTableIndex(), true); - assert vtableEntryOffset > 0; - /* - * Method pointer will always exist in the vtable due to the fact that all reachable - * methods through method pointer constant references will be compiled. - */ - AddressNode address = createOffsetAddress(graph, hub, vtableEntryOffset); - ReadNode virtualMethod = graph.add(new ReadNode(address, SubstrateBackend.getVTableIdentity(), loadMethodNode.stamp(NodeView.DEFAULT), BarrierType.NONE, MemoryOrderMode.PLAIN)); - graph.replaceFixed(loadMethodNode, virtualMethod); - - } else { - // First compute the dispatch table starting offset - LoadOpenTypeWorldDispatchTableStartingOffset tableStartingOffset = graph.add(new LoadOpenTypeWorldDispatchTableStartingOffset(hub, method)); - - // Add together table starting offset and index offset - ValueNode methodAddress = graph.unique( - new AddNode(tableStartingOffset, ConstantNode.forIntegerKind(ConfigurationValues.getWordKind(), knownOffsets.getVTableOffset(method.getVTableIndex(), false), graph))); - - // The load the method address for the dispatch table - AddressNode dispatchTableAddress = graph.unique(new OffsetAddressNode(hub, methodAddress)); - ReadNode virtualMethod = graph - .add(new ReadNode(dispatchTableAddress, SubstrateBackend.getVTableIdentity(), loadMethodNode.stamp(NodeView.DEFAULT), BarrierType.NONE, MemoryOrderMode.PLAIN)); - - // wire in the new nodes - FixedWithNextNode predecessor = (FixedWithNextNode) loadMethodNode.predecessor(); - predecessor.setNext(tableStartingOffset); - tableStartingOffset.setNext(virtualMethod); - graph.replaceFixed(loadMethodNode, virtualMethod); - - // Lower logic associated with loading starting offset - tableStartingOffset.lower(tool); - } - } - @Override public int arrayLengthOffset() { return getObjectLayout().getArrayLengthOffset(); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/nodes/LoadMethodByIndexNode.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/nodes/LoadMethodByIndexNode.java new file mode 100644 index 000000000000..803418657b84 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/nodes/LoadMethodByIndexNode.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2025, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.core.graal.nodes; + +import static jdk.graal.compiler.nodeinfo.NodeCycles.CYCLES_2; +import static jdk.graal.compiler.nodeinfo.NodeSize.SIZE_1; + +import org.graalvm.nativeimage.c.function.CodePointer; + +import jdk.graal.compiler.core.common.type.StampFactory; +import jdk.graal.compiler.graph.NodeClass; +import jdk.graal.compiler.nodeinfo.NodeInfo; +import jdk.graal.compiler.nodes.FixedWithNextNode; +import jdk.graal.compiler.nodes.ValueNode; +import jdk.graal.compiler.nodes.spi.Lowerable; +import jdk.graal.compiler.word.WordTypes; + +@NodeInfo(cycles = CYCLES_2, size = SIZE_1) +public final class LoadMethodByIndexNode extends FixedWithNextNode implements Lowerable { + public static final NodeClass TYPE = NodeClass.create(LoadMethodByIndexNode.class); + + @Input protected ValueNode hub; + @Input protected ValueNode vtableIndex; + @OptionalInput protected ValueNode interfaceTypeID; + + protected LoadMethodByIndexNode(@InjectedNodeParameter WordTypes wordTypes, ValueNode hub, ValueNode vtableIndex, ValueNode interfaceTypeID) { + super(TYPE, StampFactory.forKind(wordTypes.getWordKind())); + this.hub = hub; + this.vtableIndex = vtableIndex; + this.interfaceTypeID = interfaceTypeID; + } + + public ValueNode getHub() { + return hub; + } + + public ValueNode getVTableIndex() { + return vtableIndex; + } + + public ValueNode getInterfaceTypeID() { + return interfaceTypeID; + } + + @NodeIntrinsic + public static native CodePointer loadMethodByIndex(Object hub, int vtableIndex, int interfaceTypeID); +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/nodes/LoadOpenTypeWorldDispatchTableStartingOffset.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/nodes/LoadOpenTypeWorldDispatchTableStartingOffset.java index eccbbe13a079..0ace2403ac7a 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/nodes/LoadOpenTypeWorldDispatchTableStartingOffset.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/nodes/LoadOpenTypeWorldDispatchTableStartingOffset.java @@ -58,7 +58,7 @@ public LoadOpenTypeWorldDispatchTableStartingOffset(ValueNode hub, SharedMethod this.interfaceTypeID = null; } - protected LoadOpenTypeWorldDispatchTableStartingOffset(ValueNode hub, ValueNode interfaceTypeID) { + public LoadOpenTypeWorldDispatchTableStartingOffset(ValueNode hub, ValueNode interfaceTypeID) { super(TYPE, StampFactory.forInteger(64)); this.hub = hub; this.target = null; @@ -76,7 +76,4 @@ public ValueNode getInterfaceTypeID() { public SharedMethod getTarget() { return target; } - - @NodeIntrinsic - public static native long createOpenTypeWorldLoadDispatchTableStartingOffset(Object hub, int interfaceTypeID); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/nodes/WriteCodeBaseNode.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/nodes/WriteCodeBaseNode.java new file mode 100644 index 000000000000..3883a6d34273 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/nodes/WriteCodeBaseNode.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2025, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.core.graal.nodes; + +import org.graalvm.word.LocationIdentity; +import org.graalvm.word.PointerBase; + +import com.oracle.svm.core.FrameAccess; +import com.oracle.svm.core.ReservedRegisters; + +import jdk.graal.compiler.core.common.type.StampFactory; +import jdk.graal.compiler.graph.NodeClass; +import jdk.graal.compiler.lir.gen.LIRGeneratorTool; +import jdk.graal.compiler.nodeinfo.InputType; +import jdk.graal.compiler.nodeinfo.NodeCycles; +import jdk.graal.compiler.nodeinfo.NodeInfo; +import jdk.graal.compiler.nodeinfo.NodeSize; +import jdk.graal.compiler.nodes.FixedWithNextNode; +import jdk.graal.compiler.nodes.ValueNode; +import jdk.graal.compiler.nodes.memory.SingleMemoryKill; +import jdk.graal.compiler.nodes.spi.LIRLowerable; +import jdk.graal.compiler.nodes.spi.NodeLIRBuilderTool; + +@NodeInfo(cycles = NodeCycles.CYCLES_1, size = NodeSize.SIZE_1, allowedUsageTypes = InputType.Memory) +public class WriteCodeBaseNode extends FixedWithNextNode implements LIRLowerable, SingleMemoryKill { + public static final NodeClass TYPE = NodeClass.create(WriteCodeBaseNode.class); + + @Input protected ValueNode value; + + protected WriteCodeBaseNode(ValueNode value) { + super(TYPE, StampFactory.forVoid()); + this.value = value; + } + + @Override + public void generate(NodeLIRBuilderTool gen) { + LIRGeneratorTool tool = gen.getLIRGeneratorTool(); + tool.emitWriteRegister(ReservedRegisters.singleton().getCodeBaseRegister(), gen.operand(value), tool.getLIRKind(FrameAccess.getWordStamp())); + } + + @NodeIntrinsic + public static native void writeCurrentVMCodeBase(PointerBase value); + + /** + * Kill memory to keep memory accesses that use this register as a base from floating across + * changes of this register. + */ + @Override + public LocationIdentity getKilledLocationIdentity() { + return LocationIdentity.any(); + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/CEntryPointSnippets.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/CEntryPointSnippets.java index 934f4176973c..e006d01bdf91 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/CEntryPointSnippets.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/CEntryPointSnippets.java @@ -24,6 +24,8 @@ */ package com.oracle.svm.core.graal.snippets; +import static com.oracle.svm.core.Uninterruptible.CALLED_FROM_UNINTERRUPTIBLE_CODE; +import static com.oracle.svm.core.graal.nodes.WriteCodeBaseNode.writeCurrentVMCodeBase; import static com.oracle.svm.core.graal.nodes.WriteCurrentVMThreadNode.writeCurrentVMThread; import static com.oracle.svm.core.graal.nodes.WriteHeapBaseNode.writeCurrentVMHeapBase; import static com.oracle.svm.core.heap.RestrictHeapAccess.Access.NO_ALLOCATION; @@ -38,6 +40,7 @@ import org.graalvm.nativeimage.Isolate; import org.graalvm.nativeimage.IsolateThread; import org.graalvm.nativeimage.StackValue; +import org.graalvm.nativeimage.c.function.CodePointer; import org.graalvm.nativeimage.c.struct.SizeOf; import org.graalvm.nativeimage.c.type.CCharPointer; import org.graalvm.nativeimage.c.type.CLongPointer; @@ -69,6 +72,7 @@ import com.oracle.svm.core.c.function.CEntryPointNativeFunctions; import com.oracle.svm.core.c.locale.LocaleSupport; import com.oracle.svm.core.code.CodeInfoTable; +import com.oracle.svm.core.code.ImageCodeInfo; import com.oracle.svm.core.config.ConfigurationValues; import com.oracle.svm.core.container.Container; import com.oracle.svm.core.graal.meta.SubstrateForeignCallsProvider; @@ -85,6 +89,7 @@ import com.oracle.svm.core.imagelayer.ImageLayerSection; import com.oracle.svm.core.jdk.PlatformNativeLibrarySupport; import com.oracle.svm.core.jdk.RuntimeSupport; +import com.oracle.svm.core.layeredimagesingleton.MultiLayeredImageSingleton; import com.oracle.svm.core.log.Log; import com.oracle.svm.core.option.RuntimeOptionParser; import com.oracle.svm.core.os.CommittedMemoryProvider; @@ -197,14 +202,52 @@ static boolean hasHeapBase() { return ImageSingletons.lookup(CompressEncoding.class).hasBase(); } - @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) - public static void setHeapBase(PointerBase heapBase) { + @Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true) + private static void setHeapBase(PointerBase heapBase) { writeCurrentVMHeapBase(heapBase); if (MemoryProtectionProvider.isAvailable()) { MemoryProtectionProvider.singleton().unlockCurrentIsolate(); } } + @Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE) + @NeverInline("Heap base register is set in caller, prevent reads from floating before that.") + private static void initCodeBase() { + ImageCodeInfo imageCodeInfo = MultiLayeredImageSingleton.getForLayer(ImageCodeInfo.class, MultiLayeredImageSingleton.INITIAL_LAYER_NUMBER); + CodePointer codeBase = imageCodeInfo.getCodeStart(); + writeCurrentVMCodeBase(codeBase); + } + + /** + * Use {@link #initBaseRegisters} instead. Calling this method is not necessary unless + * heap-relative addressing is needed before the heap is fully set up. + */ + @Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true) + public static void earlyInitHeapBase(PointerBase heapBase) { + setHeapBase(heapBase); + } + + /** + * Sets the heap base register to the provided value. If the code base register is in use, + * initializes it to contain the code base address. + */ + @Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true) + public static void initBaseRegisters(PointerBase heapBase) { + setHeapBase(heapBase); + if (SubstrateOptions.useRelativeCodePointers()) { + initCodeBase(); + } + } + + /** Sets the heap base register, and if in use, the code base register, to the given values. */ + @Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true) + public static void initBaseRegisters(PointerBase heapBase, PointerBase codeBase) { + setHeapBase(heapBase); + if (SubstrateOptions.useRelativeCodePointers()) { + writeCurrentVMCodeBase(codeBase); + } + } + @Snippet(allowMissingProbabilities = true) public static int createIsolateSnippet(CEntryPointCreateIsolateParameters parameters) { writeCurrentVMThread(Word.nullPointer()); @@ -318,7 +361,7 @@ private static int createIsolate(CEntryPointCreateIsolateParameters providedPara return error; } Isolate isolate = isolatePtr.read(); - setHeapBase(Isolates.getHeapBase(isolate)); + initBaseRegisters(Isolates.getHeapBase(isolate)); return createIsolate0(isolate, arguments); } @@ -541,7 +584,7 @@ private static int enterAttachThread0(Isolate isolate, boolean startedByIsolate, if (error != CEntryPointErrors.NO_ERROR) { return error; } - setHeapBase(Isolates.getHeapBase(isolate)); + initBaseRegisters(Isolates.getHeapBase(isolate)); if (!VMThreads.isInitialized()) { return CEntryPointErrors.UNINITIALIZED_ISOLATE; } @@ -607,7 +650,7 @@ public static int enterFromCrashHandler(Isolate isolate) { @Uninterruptible(reason = "Thread state not yet set up.") public static void initializeIsolateThreadForCrashHandler(Isolate isolate, IsolateThread thread) { - setHeapBase(Isolates.getHeapBase(isolate)); + initBaseRegisters(Isolates.getHeapBase(isolate)); writeCurrentVMThread(thread); VMThreads.StatusSupport.setStatusNative(); @@ -738,7 +781,7 @@ private static int enterByIsolate(Isolate isolate) { if (error != CEntryPointErrors.NO_ERROR) { return error; } - setHeapBase(Isolates.getHeapBase(isolate)); + initBaseRegisters(Isolates.getHeapBase(isolate)); if (!VMThreads.isInitialized()) { return CEntryPointErrors.UNINITIALIZED_ISOLATE; } @@ -757,7 +800,7 @@ public static int enterSnippet(IsolateThread thread) { } writeCurrentVMThread(thread); Isolate isolate = VMThreads.IsolateTL.get(thread); - setHeapBase(Isolates.getHeapBase(isolate)); + initBaseRegisters(Isolates.getHeapBase(isolate)); if (runtimeAssertionsEnabled() || SubstrateOptions.CheckIsolateThreadAtEntry.getValue()) { /* * Verification must happen before the thread state transition. It locks the raw @@ -838,7 +881,7 @@ public static boolean isAttachedSnippet(Isolate isolate) { @Uninterruptible(reason = "Thread state not yet set up.") @SubstrateForeignCallTarget(stubCallingConvention = false) private static boolean isAttached(Isolate isolate) { - setHeapBase(Isolates.getHeapBase(isolate)); + initBaseRegisters(Isolates.getHeapBase(isolate)); return VMThreads.isInitialized() && VMThreads.singleton().findIsolateThreadForCurrentOSThread(false).isNonNull(); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/NonSnippetLowerings.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/NonSnippetLowerings.java index a38f4f1a4253..3bdb830c6f47 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/NonSnippetLowerings.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/NonSnippetLowerings.java @@ -26,7 +26,6 @@ import static jdk.graal.compiler.core.common.spi.ForeignCallDescriptor.CallSideEffect.HAS_SIDE_EFFECT; -import java.lang.reflect.Field; import java.util.ArrayList; import java.util.EnumMap; import java.util.List; @@ -36,16 +35,19 @@ import org.graalvm.word.LocationIdentity; import com.oracle.svm.core.FrameAccess; +import com.oracle.svm.core.ReservedRegisters; import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.SubstrateUtil; -import com.oracle.svm.core.c.BoxedRelocatedPointer; import com.oracle.svm.core.config.ConfigurationValues; import com.oracle.svm.core.graal.code.SubstrateBackend; import com.oracle.svm.core.graal.meta.KnownOffsets; import com.oracle.svm.core.graal.meta.RuntimeConfiguration; import com.oracle.svm.core.graal.nodes.CGlobalDataLoadAddressNode; +import com.oracle.svm.core.graal.nodes.FloatingWordCastNode; +import com.oracle.svm.core.graal.nodes.LoadMethodByIndexNode; import com.oracle.svm.core.graal.nodes.LoadOpenTypeWorldDispatchTableStartingOffset; import com.oracle.svm.core.graal.nodes.LoweredDeadEndNode; +import com.oracle.svm.core.graal.nodes.ReadReservedRegisterFixedNode; import com.oracle.svm.core.graal.nodes.ThrowBytecodeExceptionNode; import com.oracle.svm.core.imagelayer.DynamicImageLayerInfo; import com.oracle.svm.core.meta.SharedMethod; @@ -56,11 +58,12 @@ import com.oracle.svm.core.snippets.SnippetRuntime; import com.oracle.svm.core.snippets.SubstrateForeignCallTarget; import com.oracle.svm.core.util.VMError; -import com.oracle.svm.util.ReflectionUtil; import jdk.graal.compiler.core.common.memory.BarrierType; import jdk.graal.compiler.core.common.memory.MemoryOrderMode; import jdk.graal.compiler.core.common.spi.ForeignCallDescriptor; +import jdk.graal.compiler.core.common.type.Stamp; +import jdk.graal.compiler.core.common.type.StampFactory; import jdk.graal.compiler.core.common.type.StampPair; import jdk.graal.compiler.core.common.type.TypeReference; import jdk.graal.compiler.graph.Node; @@ -87,6 +90,8 @@ import jdk.graal.compiler.nodes.ValueNode; import jdk.graal.compiler.nodes.calc.AddNode; import jdk.graal.compiler.nodes.calc.IsNullNode; +import jdk.graal.compiler.nodes.calc.MulNode; +import jdk.graal.compiler.nodes.calc.ZeroExtendNode; import jdk.graal.compiler.nodes.extended.BranchProbabilityNode; import jdk.graal.compiler.nodes.extended.BytecodeExceptionNode; import jdk.graal.compiler.nodes.extended.BytecodeExceptionNode.BytecodeExceptionKind; @@ -94,6 +99,7 @@ import jdk.graal.compiler.nodes.extended.ForeignCallNode; import jdk.graal.compiler.nodes.extended.GetClassNode; import jdk.graal.compiler.nodes.extended.LoadHubNode; +import jdk.graal.compiler.nodes.extended.LoadMethodNode; import jdk.graal.compiler.nodes.extended.OpaqueValueNode; import jdk.graal.compiler.nodes.java.InstanceOfNode; import jdk.graal.compiler.nodes.java.MethodCallTargetNode; @@ -120,7 +126,6 @@ public abstract class NonSnippetLowerings { public static final SnippetRuntime.SubstrateForeignCallDescriptor REPORT_VERIFY_TYPES_ERROR = SnippetRuntime.findForeignCall(NonSnippetLowerings.class, "reportVerifyTypesError", HAS_SIDE_EFFECT, LocationIdentity.any()); - public static final Field boxedRelocatedPointerField = ReflectionUtil.lookupField(BoxedRelocatedPointer.class, "pointer"); private final Predicate mustNotAllocatePredicate; @@ -136,10 +141,17 @@ protected NonSnippetLowerings(RuntimeConfiguration runtimeConfig, Predicate getCachedExceptionDescriptors; @@ -295,12 +307,16 @@ public static class InvokeLowering implements NodeLoweringProvider { protected final boolean verifyTypes; protected final KnownOffsets knownOffsets; private final boolean isClosedTypeWorld; + private final boolean haveClosedTypeWorldHubLayout; + private final LoadMethodTool loadMethodTool; public InvokeLowering(RuntimeConfiguration runtimeConfig, boolean verifyTypes, KnownOffsets knownOffsets) { this.runtimeConfig = runtimeConfig; this.verifyTypes = verifyTypes; this.knownOffsets = knownOffsets; - isClosedTypeWorld = SubstrateOptions.useClosedTypeWorld(); + this.isClosedTypeWorld = SubstrateOptions.useClosedTypeWorld(); + this.haveClosedTypeWorldHubLayout = SubstrateOptions.useClosedTypeWorldHubLayout(); + this.loadMethodTool = new LoadMethodTool(runtimeConfig, knownOffsets); } @Override @@ -438,45 +454,26 @@ public void lower(FixedNode node, LoweringTool tool) { loweredCallTarget = createUnreachableCallTarget(tool, node, parameters, callTarget.returnStamp(), signature, method, callType, invokeKind); } else { - LoadHubNode hub = graph.unique(new LoadHubNode(runtimeConfig.getProviders().getStampProvider(), graph.addOrUnique(PiNode.create(receiver, nullCheck)))); + StampProvider stampProvider = runtimeConfig.getProviders().getStampProvider(); + LoadHubNode hub = graph.unique(new LoadHubNode(stampProvider, graph.addOrUnique(PiNode.create(receiver, nullCheck)))); nodesToLower.add(hub); - if (SubstrateOptions.useClosedTypeWorldHubLayout()) { - int vtableEntryOffset = knownOffsets.getVTableOffset(method.getVTableIndex(), true); - - AddressNode address = graph.unique(new OffsetAddressNode(hub, ConstantNode.forIntegerKind(ConfigurationValues.getWordKind(), vtableEntryOffset, graph))); - ReadNode entry = graph.add(new ReadNode(address, SubstrateBackend.getVTableIdentity(), FrameAccess.getWordStamp(), BarrierType.NONE, MemoryOrderMode.PLAIN)); - - loweredCallTarget = createIndirectCall(graph, callTarget, parameters, method, signature, callType, invokeKind, entry); - - graph.addBeforeFixed(node, entry); - } else { - - // Compute the dispatch table starting offset - LoadOpenTypeWorldDispatchTableStartingOffset tableStartingOffset = graph.add(new LoadOpenTypeWorldDispatchTableStartingOffset(hub, method)); - nodesToLower.add(tableStartingOffset); - - // Add together table starting offset and index offset - ValueNode methodAddressOffset = graph.unique(new AddNode(tableStartingOffset, - ConstantNode.forIntegerKind(ConfigurationValues.getWordKind(), knownOffsets.getVTableOffset(method.getVTableIndex(), false), graph))); - - // The load the method address for the dispatch table - AddressNode dispatchTableAddress = graph.unique(new OffsetAddressNode(hub, methodAddressOffset)); - ReadNode entry = graph.add(new ReadNode(dispatchTableAddress, SubstrateBackend.getVTableIdentity(), FrameAccess.getWordStamp(), BarrierType.NONE, MemoryOrderMode.PLAIN)); + LoadOpenTypeWorldDispatchTableStartingOffset openWorldDispatchTableOffset = null; + if (!haveClosedTypeWorldHubLayout) { + openWorldDispatchTableOffset = graph.add(new LoadOpenTypeWorldDispatchTableStartingOffset(hub, method)); + graph.addBeforeFixed(node, openWorldDispatchTableOffset); + nodesToLower.add(openWorldDispatchTableOffset); + } - loweredCallTarget = createIndirectCall(graph, callTarget, parameters, method, signature, callType, invokeKind, entry); + ConstantNode vtableIndex = ConstantNode.forInt(method.getVTableIndex(), graph); + ValueNode callAddress = loadMethodTool.createVirtualMethodAddressLoad(node, hub, openWorldDispatchTableOffset, vtableIndex, stampProvider.createMethodStamp()); - // wire in the new nodes - FixedWithNextNode predecessor = (FixedWithNextNode) node.predecessor(); - predecessor.setNext(tableStartingOffset); - tableStartingOffset.setNext(entry); - entry.setNext(node); + loweredCallTarget = createIndirectCall(graph, callTarget, parameters, method, signature, callType, invokeKind, callAddress); - /* - * note here we don't delete the invoke because it remains in the graph, - * albeit with a different call target - */ - } + /* + * note here we don't delete the invoke because it remains in the graph, albeit + * with a different call target + */ } callTarget.replaceAndDelete(loweredCallTarget); @@ -517,6 +514,115 @@ private static CallTargetNode createUnreachableCallTarget(LoweringTool tool, Fix } } + static final class LoadMethodLowering implements NodeLoweringProvider { + private final LoadMethodTool loadTool; + private final boolean haveClosedWorldHubLayout; + + LoadMethodLowering(RuntimeConfiguration runtimeConfig, KnownOffsets knownOffsets) { + this.loadTool = new LoadMethodTool(runtimeConfig, knownOffsets); + this.haveClosedWorldHubLayout = SubstrateOptions.useClosedTypeWorldHubLayout(); + } + + @Override + public void lower(FixedWithNextNode node, LoweringTool tool) { + if (node instanceof LoadMethodNode ln) { + lowerLoadMethodNode(ln, tool); + } else if (node instanceof LoadMethodByIndexNode ln) { + lowerLoadMethodByIndexNode(ln, tool); + } + } + + private void lowerLoadMethodNode(LoadMethodNode node, LoweringTool tool) { + StructuredGraph graph = node.graph(); + SharedMethod method = (SharedMethod) node.getMethod(); + int vtableIndex = method.getVTableIndex(); + ConstantNode vtableIndexNode = ConstantNode.forIntegerKind(loadTool.runtimeConfig.getProviders().getWordTypes().getWordKind(), vtableIndex, graph); + LoadOpenTypeWorldDispatchTableStartingOffset tableStartOffset = null; + if (!haveClosedWorldHubLayout) { + tableStartOffset = graph.add(new LoadOpenTypeWorldDispatchTableStartingOffset(node.getHub(), method)); + } + lowerLoadMethod(node, node.getHub(), tool, vtableIndexNode, tableStartOffset); + } + + private void lowerLoadMethodByIndexNode(LoadMethodByIndexNode node, LoweringTool tool) { + LoadOpenTypeWorldDispatchTableStartingOffset tableStartOffset = null; + if (!haveClosedWorldHubLayout) { + tableStartOffset = node.graph().add(new LoadOpenTypeWorldDispatchTableStartingOffset(node.getHub(), node.getInterfaceTypeID())); + } + lowerLoadMethod(node, node.getHub(), tool, node.getVTableIndex(), tableStartOffset); + } + + private void lowerLoadMethod(FixedWithNextNode loadMethodNode, ValueNode hub, LoweringTool tool, ValueNode vtableIndex, + LoadOpenTypeWorldDispatchTableStartingOffset openWorldDispatchTableOffset) { + StructuredGraph graph = loadMethodNode.graph(); + + if (openWorldDispatchTableOffset != null) { + graph.addBeforeFixed(loadMethodNode, openWorldDispatchTableOffset); + } + + ValueNode virtualMethod = loadTool.createVirtualMethodAddressLoad(loadMethodNode, hub, openWorldDispatchTableOffset, vtableIndex, loadMethodNode.stamp(NodeView.DEFAULT)); + graph.replaceFixed(loadMethodNode, virtualMethod); + + if (openWorldDispatchTableOffset != null) { + openWorldDispatchTableOffset.lower(tool); + } + } + } + + static final class LoadMethodTool { + private final RuntimeConfiguration runtimeConfig; + private final KnownOffsets knownOffsets; + private final boolean relativeCodePointers; + + LoadMethodTool(RuntimeConfiguration runtimeConfig, KnownOffsets knownOffsets) { + this.runtimeConfig = runtimeConfig; + this.knownOffsets = knownOffsets; + this.relativeCodePointers = SubstrateOptions.useRelativeCodePointers(); + } + + ValueNode createVirtualMethodAddressLoad( + FixedNode prependTo, ValueNode hub, LoadOpenTypeWorldDispatchTableStartingOffset openWorldDispatchTableOffset, ValueNode vtableIndex, Stamp resultStamp) { + + StructuredGraph graph = prependTo.graph(); + JavaKind wordKind = runtimeConfig.getProviders().getWordTypes().getWordKind(); + + int entrySizeValue = knownOffsets.getVTableEntrySize(); + ConstantNode entrySize = ConstantNode.forIntegerKind(wordKind, entrySizeValue, graph); + ValueNode vtableIndexWord = graph.unique(new ZeroExtendNode(vtableIndex, wordKind.getBitCount())); + ValueNode vtableEntryOffset = graph.unique(new MulNode(vtableIndexWord, entrySize)); + + ValueNode baseOffset; + assert SubstrateOptions.useClosedTypeWorldHubLayout() == (openWorldDispatchTableOffset == null); + if (openWorldDispatchTableOffset != null) { + baseOffset = openWorldDispatchTableOffset; + } else { + int baseOffsetValue = knownOffsets.getVTableBaseOffset(); + baseOffset = ConstantNode.forIntegerKind(wordKind, baseOffsetValue, graph); + } + + ValueNode hubEntryOffset = graph.unique(new AddNode(baseOffset, vtableEntryOffset)); + AddressNode entryAddress = graph.unique(new OffsetAddressNode(hub, hubEntryOffset)); + ReadNode vtableEntry = graph.add(new ReadNode(entryAddress, SubstrateBackend.getVTableIdentity(), StampFactory.forKind(wordKind), BarrierType.NONE, MemoryOrderMode.PLAIN)); + graph.addBeforeFixed(prependTo, vtableEntry); + + ValueNode virtualMethodAddress; + if (relativeCodePointers) { + /* + * GR-64589: this can be a floating read outside of deoptimization target methods, + * but this code has no knowledge of deoptimization (class ReadReservedRegister). + */ + FixedWithNextNode codeBase = graph.add(new ReadReservedRegisterFixedNode(ReservedRegisters.singleton().getCodeBaseRegister())); + graph.addBeforeFixed(prependTo, codeBase); + + virtualMethodAddress = graph.unique(new AddNode(vtableEntry, codeBase)); + } else { + virtualMethodAddress = vtableEntry; + } + + return graph.unique(new FloatingWordCastNode(resultStamp, virtualMethodAddress)); + } + } + @SubstrateForeignCallTarget(stubCallingConvention = true) private static void reportVerifyTypesError(Object object, String message) { throw VMError.shouldNotReachHere("VerifyTypes: object=" + (object == null ? "null" : object.getClass().getTypeName()) + diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java index ca505f803539..9907b4d93a52 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java @@ -87,7 +87,7 @@ import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; -import org.graalvm.nativeimage.c.function.CFunctionPointer; +import org.graalvm.word.WordBase; import com.oracle.svm.core.BuildPhaseProvider.AfterHostedUniverse; import com.oracle.svm.core.BuildPhaseProvider.CompileQueueFinished; @@ -354,7 +354,7 @@ public final class DynamicHub implements AnnotatedElement, java.lang.reflect.Typ private final byte layerId; @UnknownObjectField(availability = AfterHostedUniverse.class)// - private CFunctionPointer[] vtable; + private WordBase[] vtable; private final DynamicHubCompanion companion; @@ -589,7 +589,7 @@ public void setSharedData(int layoutEncoding, int monitorOffset, int identityHas } @Platforms(Platform.HOSTED_ONLY.class) - public void setClosedTypeWorldData(CFunctionPointer[] vtable, int typeID, short typeCheckStart, short typeCheckRange, short typeCheckSlot, short[] typeCheckSlots) { + public void setClosedTypeWorldData(WordBase[] vtable, int typeID, short typeCheckStart, short typeCheckRange, short typeCheckSlot, short[] typeCheckSlots) { assert this.vtable == null : "Initialization must be called only once"; this.typeID = typeID; @@ -601,8 +601,7 @@ public void setClosedTypeWorldData(CFunctionPointer[] vtable, int typeID, short } @Platforms(Platform.HOSTED_ONLY.class) - public void setOpenTypeWorldData(CFunctionPointer[] vtable, int typeID, - int typeCheckDepth, int numClassTypes, int numInterfaceTypes, int[] typeCheckSlots) { + public void setOpenTypeWorldData(WordBase[] vtable, int typeID, int typeCheckDepth, int numClassTypes, int numInterfaceTypes, int[] typeCheckSlots) { assert this.vtable == null : "Initialization must be called only once"; this.typeID = typeID; diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/access/JNIAccessibleMethod.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/access/JNIAccessibleMethod.java index 4970170fda73..5eabc6ac1a4d 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/access/JNIAccessibleMethod.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/access/JNIAccessibleMethod.java @@ -26,7 +26,6 @@ import java.lang.reflect.Modifier; -import jdk.graal.compiler.word.Word; import org.graalvm.collections.EconomicSet; import org.graalvm.nativeimage.Platform.HOSTED_ONLY; import org.graalvm.nativeimage.Platforms; @@ -35,17 +34,14 @@ import com.oracle.svm.core.AlwaysInline; import com.oracle.svm.core.BuildPhaseProvider.ReadyForCompilation; -import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.Uninterruptible; import com.oracle.svm.core.code.RuntimeMetadataDecoderImpl; -import com.oracle.svm.core.graal.nodes.LoadOpenTypeWorldDispatchTableStartingOffset; +import com.oracle.svm.core.graal.nodes.LoadMethodByIndexNode; import com.oracle.svm.core.heap.UnknownPrimitiveField; import com.oracle.svm.core.jni.CallVariant; import com.oracle.svm.core.util.VMError; import com.oracle.svm.util.ReflectionUtil; -import jdk.graal.compiler.nodes.NamedLocationIdentity; -import jdk.graal.compiler.word.BarrieredAccess; import jdk.vm.ci.meta.MetaAccessProvider; import jdk.vm.ci.meta.ResolvedJavaField; @@ -53,12 +49,12 @@ * Information on a method that can be looked up and called via JNI. */ public final class JNIAccessibleMethod extends JNIAccessibleMember { - public static final int STATICALLY_BOUND_METHOD = -1; - public static final int VTABLE_OFFSET_NOT_YET_COMPUTED = -2; + public static final int VTABLE_INDEX_STATICALLY_BOUND_METHOD = -1; + public static final int VTABLE_INDEX_NOT_YET_COMPUTED = -2; public static final int INTERFACE_TYPEID_CLASS_TABLE = -1; public static final int INTERFACE_TYPEID_NOT_YET_COMPUTED = -2; public static final int INTERFACE_TYPEID_UNNEEDED = -3; - public static final int NEW_OBJECT_INVALID_FOR_ABSTRACT_TYPE = -1; + public static final int NEW_OBJECT_TARGET_INVALID_FOR_ABSTRACT_TYPE = -1; public static JNIAccessibleMethod negativeMethodQuery(JNIAccessibleClass jniClass) { return new JNIAccessibleMethod(jniClass, RuntimeMetadataDecoderImpl.NEGATIVE_FLAG_MASK); @@ -85,7 +81,7 @@ public static ResolvedJavaField getCallVariantWrapperField(MetaAccessProvider me private final int modifiers; @UnknownPrimitiveField(availability = ReadyForCompilation.class)// - private int vtableOffset = VTABLE_OFFSET_NOT_YET_COMPUTED; + private int vtableIndex = VTABLE_INDEX_NOT_YET_COMPUTED; @UnknownPrimitiveField(availability = ReadyForCompilation.class)// private int interfaceTypeID = INTERFACE_TYPEID_NOT_YET_COMPUTED; @UnknownPrimitiveField(availability = ReadyForCompilation.class)// @@ -128,15 +124,9 @@ CodePointer getCallWrapperAddress() { @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) CodePointer getJavaCallAddress(Object instance, boolean nonVirtual) { if (!nonVirtual) { - assert vtableOffset != JNIAccessibleMethod.VTABLE_OFFSET_NOT_YET_COMPUTED; - if (vtableOffset != JNIAccessibleMethod.STATICALLY_BOUND_METHOD) { - if (SubstrateOptions.useClosedTypeWorldHubLayout()) { - return BarrieredAccess.readWord(instance.getClass(), vtableOffset, NamedLocationIdentity.FINAL_LOCATION); - } else { - long tableStartingOffset = LoadOpenTypeWorldDispatchTableStartingOffset.createOpenTypeWorldLoadDispatchTableStartingOffset(instance.getClass(), interfaceTypeID); - - return BarrieredAccess.readWord(instance.getClass(), Word.pointer(tableStartingOffset + vtableOffset), NamedLocationIdentity.FINAL_LOCATION); - } + assert vtableIndex != JNIAccessibleMethod.VTABLE_INDEX_NOT_YET_COMPUTED && interfaceTypeID != INTERFACE_TYPEID_NOT_YET_COMPUTED; + if (vtableIndex != JNIAccessibleMethod.VTABLE_INDEX_STATICALLY_BOUND_METHOD) { + return LoadMethodByIndexNode.loadMethodByIndex(instance.getClass(), vtableIndex, interfaceTypeID); } } return nonvirtualTarget; @@ -163,13 +153,13 @@ boolean isStatic() { } @Platforms(HOSTED_ONLY.class) - public void finishBeforeCompilation(EconomicSet> hidingSubclasses, int vtableOffsetEntry, int interfaceTypeIDEntry, CodePointer nonvirtualEntry, PointerBase newObjectEntry, + public void finishBeforeCompilation(EconomicSet> hidingSubclasses, int vtableIndexEntry, int interfaceTypeIDEntry, CodePointer nonvirtualEntry, PointerBase newObjectEntry, CodePointer callWrapperEntry, CodePointer varargs, CodePointer array, CodePointer valist, CodePointer varargsNonvirtual, CodePointer arrayNonvirtual, CodePointer valistNonvirtual) { - assert this.vtableOffset == VTABLE_OFFSET_NOT_YET_COMPUTED && (vtableOffsetEntry == STATICALLY_BOUND_METHOD || vtableOffsetEntry >= 0); + assert this.vtableIndex == VTABLE_INDEX_NOT_YET_COMPUTED && (vtableIndexEntry == VTABLE_INDEX_STATICALLY_BOUND_METHOD || vtableIndexEntry >= 0); assert this.interfaceTypeID == INTERFACE_TYPEID_NOT_YET_COMPUTED && interfaceTypeIDEntry != INTERFACE_TYPEID_NOT_YET_COMPUTED; - this.vtableOffset = vtableOffsetEntry; + this.vtableIndex = vtableIndexEntry; this.interfaceTypeID = interfaceTypeIDEntry; this.nonvirtualTarget = nonvirtualEntry; this.newObjectTarget = newObjectEntry; diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/layeredimagesingleton/MultiLayeredImageSingleton.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/layeredimagesingleton/MultiLayeredImageSingleton.java index 25309e98f633..3ae583554a6c 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/layeredimagesingleton/MultiLayeredImageSingleton.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/layeredimagesingleton/MultiLayeredImageSingleton.java @@ -39,6 +39,7 @@ public interface MultiLayeredImageSingleton extends LayeredImageSingleton { */ int UNUSED_LAYER_NUMBER = -1; int UNKNOWN_LAYER_NUMBER = 0; + int INITIAL_LAYER_NUMBER = 0; /** * Returns an array containing the image singletons installed for {@code key} within all layers. diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/meta/MethodOffset.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/meta/MethodOffset.java new file mode 100644 index 000000000000..d44868968361 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/meta/MethodOffset.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2025, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.core.meta; + +import static com.oracle.svm.core.util.VMError.shouldNotReachHere; + +import java.util.Objects; + +import org.graalvm.word.WordBase; + +import com.oracle.svm.core.util.VMError; + +import jdk.vm.ci.meta.ResolvedJavaMethod; + +/** The offset of the compiled code of a method from the code base. */ +public final class MethodOffset implements WordBase { + private final ResolvedJavaMethod method; + + public MethodOffset(ResolvedJavaMethod method) { + this.method = Objects.requireNonNull(method); + } + + public ResolvedJavaMethod getMethod() { + return method; + } + + @Override + public long rawValue() { + throw shouldNotReachHere("must not be called in hosted mode"); + } + + @SuppressWarnings("deprecation") + @Deprecated + @Override + public boolean equals(Object obj) { + throw VMError.shouldNotReachHere("equals() not supported on words"); + } + + @Override + public int hashCode() { + throw VMError.shouldNotReachHere("hashCode() not supported on words"); + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/meta/MethodPointer.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/meta/MethodPointer.java index 6cac7506a941..9122d5e9bfa1 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/meta/MethodPointer.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/meta/MethodPointer.java @@ -38,24 +38,24 @@ */ public final class MethodPointer implements CFunctionPointer { private final ResolvedJavaMethod method; - private final boolean isAbsolute; + private final boolean permitsRewriteToPLT; - public MethodPointer(ResolvedJavaMethod method, boolean isAbsolute) { + public MethodPointer(ResolvedJavaMethod method, boolean permitsRewriteToPLT) { Objects.requireNonNull(method); this.method = method; - this.isAbsolute = isAbsolute; + this.permitsRewriteToPLT = permitsRewriteToPLT; } public MethodPointer(ResolvedJavaMethod method) { - this(method, false); + this(method, true); } public ResolvedJavaMethod getMethod() { return method; } - public boolean isAbsolute() { - return isAbsolute; + public boolean permitsRewriteToPLT() { + return permitsRewriteToPLT; } @Override diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/meta/SubstrateMethodOffsetConstant.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/meta/SubstrateMethodOffsetConstant.java new file mode 100644 index 000000000000..50fe89f2bfec --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/meta/SubstrateMethodOffsetConstant.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2025, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.core.meta; + +import java.util.Objects; + +import com.oracle.svm.core.snippets.KnownIntrinsics; + +import jdk.vm.ci.meta.VMConstant; + +/** + * Constant for the offset of a compiled method from the {@link KnownIntrinsics#codeBase()}. The + * value is patched when writing the image. + * + * At this time, code offset constants are required only in the heap. When supporting embedding them + * in code, this class could be merged with {@link SubstrateMethodPointerConstant}. + */ +public class SubstrateMethodOffsetConstant implements VMConstant { + + private final MethodOffset offset; + + public SubstrateMethodOffsetConstant(MethodOffset offset) { + this.offset = Objects.requireNonNull(offset); + } + + public MethodOffset offset() { + return offset; + } + + @Override + public boolean isDefaultForKind() { + return false; + } + + @Override + public String toValueString() { + return SubstrateMethodOffsetConstant.class.getSimpleName(); + } + + @Override + public String toString() { + return "method offset: " + offset.getMethod().format("%H.%n"); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + return obj instanceof SubstrateMethodOffsetConstant other && offset.getMethod().equals(other.offset.getMethod()); + } + + @Override + public int hashCode() { + return Objects.hashCode(offset.getMethod()); + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/pltgot/PLTGOTConfiguration.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/pltgot/PLTGOTConfiguration.java index f880c0b20f3c..04a902cab43b 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/pltgot/PLTGOTConfiguration.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/pltgot/PLTGOTConfiguration.java @@ -35,6 +35,11 @@ public abstract class PLTGOTConfiguration { protected MethodAddressResolver methodAddressResolver; + @Fold + public static boolean isEnabled() { + return ImageSingletons.contains(PLTGOTConfiguration.class); + } + @Fold public static PLTGOTConfiguration singleton() { return ImageSingletons.lookup(PLTGOTConfiguration.class); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/SubstrateMethodAccessor.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/SubstrateMethodAccessor.java index 6189187e50fa..1a3836f2caf0 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/SubstrateMethodAccessor.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/SubstrateMethodAccessor.java @@ -26,22 +26,18 @@ import java.lang.reflect.Executable; -import jdk.graal.compiler.word.Word; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; import org.graalvm.nativeimage.c.function.CFunctionPointer; -import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.classinitialization.EnsureClassInitializedNode; -import com.oracle.svm.core.graal.nodes.LoadOpenTypeWorldDispatchTableStartingOffset; +import com.oracle.svm.core.graal.nodes.LoadMethodByIndexNode; import com.oracle.svm.core.hub.DynamicHub; import com.oracle.svm.core.jdk.InternalVMMethod; import com.oracle.svm.core.reflect.ReflectionAccessorHolder.MethodInvokeFunctionPointer; import com.oracle.svm.core.reflect.ReflectionAccessorHolder.MethodInvokeFunctionPointerForCallerSensitiveAdapter; import com.oracle.svm.core.util.VMError; -import jdk.graal.compiler.nodes.NamedLocationIdentity; -import jdk.graal.compiler.word.BarrieredAccess; import jdk.internal.reflect.MethodAccessor; import jdk.vm.ci.meta.ResolvedJavaMethod; @@ -52,9 +48,12 @@ interface MethodAccessorJDK19 { @InternalVMMethod public final class SubstrateMethodAccessor extends SubstrateAccessor implements MethodAccessor, MethodAccessorJDK19 { - public static final int STATICALLY_BOUND = -1; - public static final int OFFSET_NOT_YET_COMPUTED = 0xdead0001; + public static final int VTABLE_INDEX_STATICALLY_BOUND = -1; + public static final int VTABLE_INDEX_NOT_YET_COMPUTED = -2; + public static final int INTERFACE_TYPEID_CLASS_TABLE = -1; + public static final int INTERFACE_TYPEID_NOT_YET_COMPUTED = 0xdead0001; + public static final int INTERFACE_TYPEID_UNNEEDED = -3; /** * The expected receiver type, which is checked before invoking the {@link #expandSignature} @@ -62,22 +61,22 @@ public final class SubstrateMethodAccessor extends SubstrateAccessor implements */ private final Class receiverType; /** The actual value is computed after static analysis using a field value transformer. */ - private int vtableOffset; + private int vtableIndex; private int interfaceTypeID; private final boolean callerSensitiveAdapter; @Platforms(Platform.HOSTED_ONLY.class) - public SubstrateMethodAccessor(Executable member, Class receiverType, CFunctionPointer expandSignature, CFunctionPointer directTarget, ResolvedJavaMethod targetMethod, int vtableOffset, + public SubstrateMethodAccessor(Executable member, Class receiverType, CFunctionPointer expandSignature, CFunctionPointer directTarget, ResolvedJavaMethod targetMethod, int vtableIndex, DynamicHub initializeBeforeInvoke, boolean callerSensitiveAdapter) { super(member, expandSignature, directTarget, targetMethod, initializeBeforeInvoke); this.receiverType = receiverType; - this.vtableOffset = vtableOffset; - this.interfaceTypeID = OFFSET_NOT_YET_COMPUTED; + this.vtableIndex = vtableIndex; + this.interfaceTypeID = INTERFACE_TYPEID_NOT_YET_COMPUTED; this.callerSensitiveAdapter = callerSensitiveAdapter; } - public int getVTableOffset() { - return vtableOffset; + public int getVTableIndex() { + return vtableIndex; } public int getInterfaceTypeID() { @@ -103,29 +102,15 @@ private void preInvoke(Object obj) { private CFunctionPointer invokeTarget(Object obj) { /* - * In case we have both a vtableOffset and a directTarget, the vtable lookup wins. For such + * In case we have both a vtableIndex and a directTarget, the vtable lookup wins. For such * methods, the directTarget is only used when doing an invokeSpecial. */ - CFunctionPointer target; - if (vtableOffset == OFFSET_NOT_YET_COMPUTED) { - throw VMError.shouldNotReachHere("Missed vtableOffset recomputation at image build time"); - } else if (vtableOffset != STATICALLY_BOUND) { - if (SubstrateOptions.useClosedTypeWorldHubLayout()) { - target = BarrieredAccess.readWord(obj.getClass(), vtableOffset, NamedLocationIdentity.FINAL_LOCATION); - } else { - long tableStartingOffset = LoadOpenTypeWorldDispatchTableStartingOffset.createOpenTypeWorldLoadDispatchTableStartingOffset(obj.getClass(), interfaceTypeID); - - /* - * Must also add in the vtable base offset as well as the offset within the table. - */ - long methodOffset = tableStartingOffset + vtableOffset; - - target = BarrieredAccess.readWord(obj.getClass(), Word.pointer(methodOffset), NamedLocationIdentity.FINAL_LOCATION); - } + VMError.guarantee(vtableIndex != VTABLE_INDEX_NOT_YET_COMPUTED && interfaceTypeID != INTERFACE_TYPEID_NOT_YET_COMPUTED, "Missed recomputation at image build time"); + if (vtableIndex == VTABLE_INDEX_STATICALLY_BOUND) { + return directTarget; } else { - target = directTarget; + return (CFunctionPointer) LoadMethodByIndexNode.loadMethodByIndex(obj.getClass(), vtableIndex, interfaceTypeID); } - return target; } @Override diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/sampler/SubstrateSigprofHandler.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/sampler/SubstrateSigprofHandler.java index 285c70a2a5a9..785ca86b9a3e 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/sampler/SubstrateSigprofHandler.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/sampler/SubstrateSigprofHandler.java @@ -203,7 +203,7 @@ protected static boolean tryEnterIsolate() { } /* Write isolate pointer (heap base) into register. */ - CEntryPointSnippets.setHeapBase(Isolates.getHeapBase(isolate)); + CEntryPointSnippets.initBaseRegisters(Isolates.getHeapBase(isolate)); /* We are keeping reference to isolate thread inside OS thread local area. */ ThreadLocalKey key = singleton().keyForNativeThreadLocal; diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/snippets/KnownIntrinsics.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/snippets/KnownIntrinsics.java index d24ce1fafc85..ac040a0edba4 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/snippets/KnownIntrinsics.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/snippets/KnownIntrinsics.java @@ -41,6 +41,12 @@ public class KnownIntrinsics { */ public static native Pointer heapBase(); + /** + * Returns the value of the code base, which is the address which + * {@linkplain com.oracle.svm.core.meta.MethodOffset method offsets} are relative to. + */ + public static native Pointer codeBase(); + /** * Returns the hub of the given object. */ diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SVMHost.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SVMHost.java index 1a21c48050eb..5c1397614a10 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SVMHost.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SVMHost.java @@ -124,7 +124,7 @@ import com.oracle.svm.hosted.meta.HostedField; import com.oracle.svm.hosted.meta.HostedType; import com.oracle.svm.hosted.meta.HostedUniverse; -import com.oracle.svm.hosted.meta.RelocatableConstant; +import com.oracle.svm.hosted.meta.PatchedWordConstant; import com.oracle.svm.hosted.phases.AnalysisGraphBuilderPhase; import com.oracle.svm.hosted.phases.ImplicitAssertionsPhase; import com.oracle.svm.hosted.phases.InlineBeforeAnalysisGraphDecoderImpl; @@ -358,7 +358,7 @@ public void recordActivity() { @Override public boolean isRelocatedPointer(JavaConstant constant) { - return constant instanceof RelocatableConstant; + return constant instanceof PatchedWordConstant; } @Override diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java index 2d36165c87c9..0185470e6b48 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java @@ -49,7 +49,7 @@ import com.oracle.svm.hosted.SVMHost; import com.oracle.svm.hosted.classinitialization.ClassInitializationSupport; import com.oracle.svm.hosted.classinitialization.SimulateClassInitializerSupport; -import com.oracle.svm.hosted.meta.RelocatableConstant; +import com.oracle.svm.hosted.meta.PatchedWordConstant; import jdk.graal.compiler.nodes.spi.IdentityHashCodeProvider; import jdk.vm.ci.meta.Constant; @@ -95,7 +95,7 @@ public Integer identityHashCode(JavaConstant constant) { } else if (constant.isNull()) { /* System.identityHashCode is specified to return 0 when passed null. */ return 0; - } else if (constant instanceof RelocatableConstant) { + } else if (constant instanceof PatchedWordConstant) { /* Kind of a primitive constant, so it does not have an identity hash code. */ return null; } @@ -200,7 +200,7 @@ private static JavaConstant checkExpectedValue(JavaConstant value) { } private static boolean isExpectedJavaConstant(JavaConstant value) { - return value.isNull() || value.getJavaKind().isPrimitive() || value instanceof RelocatableConstant || value instanceof ImageHeapConstant; + return value.isNull() || value.getJavaKind().isPrimitive() || value instanceof PatchedWordConstant || value instanceof ImageHeapConstant; } @Override diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/SVMHostedValueProvider.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/SVMHostedValueProvider.java index 7f1d1eeb0cae..692601da030e 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/SVMHostedValueProvider.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/SVMHostedValueProvider.java @@ -37,10 +37,11 @@ import com.oracle.graal.pointsto.meta.AnalysisUniverse; import com.oracle.graal.pointsto.util.AnalysisError; import com.oracle.svm.core.config.ConfigurationValues; +import com.oracle.svm.core.meta.MethodOffset; import com.oracle.svm.core.meta.SubstrateObjectConstant; import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.classinitialization.SimulateClassInitializerSupport; -import com.oracle.svm.hosted.meta.RelocatableConstant; +import com.oracle.svm.hosted.meta.PatchedWordConstant; import jdk.vm.ci.meta.ConstantReflectionProvider; import jdk.vm.ci.meta.JavaConstant; @@ -99,13 +100,13 @@ public JavaConstant readArrayElement(JavaConstant array, int index) { } /** - * {@link #forObject} replaces relocatable pointers with {@link RelocatableConstant} and regular - * {@link WordBase} values with {@link PrimitiveConstant}. No other {@link WordBase} values can - * be reachable at this point. + * {@link #forObject} replaces patched words such as relocatable pointers with + * {@link PatchedWordConstant}, and regular {@link WordBase} values with + * {@link PrimitiveConstant}. No other {@link WordBase} values can be reachable at this point. */ @Override public JavaConstant validateReplacedConstant(JavaConstant value) { - VMError.guarantee(value instanceof RelocatableConstant || !universe.getBigbang().getMetaAccess().isInstanceOf(value, WordBase.class)); + VMError.guarantee(value instanceof PatchedWordConstant || !universe.getBigbang().getMetaAccess().isInstanceOf(value, WordBase.class)); return value; } @@ -118,8 +119,8 @@ public JavaConstant forObject(Object object) { @Override public T asObject(Class type, JavaConstant constant) { - if (constant instanceof RelocatableConstant relocatable) { - return type.cast(relocatable.getPointer()); + if (constant instanceof PatchedWordConstant pwc) { + return type.cast(pwc.getWord()); } return super.asObject(type, constant); } @@ -156,17 +157,18 @@ public JavaConstant interceptHosted(JavaConstant constant) { /** * Intercept {@link WordBase} constants and: *
    - *
  • replace {@link RelocatedPointer} constants with {@link RelocatableConstant} to easily and - * reliably distinguish them from other {@link WordBase} values during image build.
  • + *
  • replace {@link RelocatedPointer} and {@link MethodOffset} constants with + * {@link PatchedWordConstant} to easily and reliably distinguish them from other + * {@link WordBase} values during image build.
  • *
  • replace regular {@link WordBase} values with corresponding integer kind * {@link PrimitiveConstant}.
  • *
*/ private Optional interceptWordType(Object object) { - if (object instanceof RelocatedPointer pointer) { - return Optional.of(new RelocatableConstant(pointer, metaAccess.lookupJavaType(object.getClass()))); - } if (object instanceof WordBase word) { + if (object instanceof RelocatedPointer || object instanceof MethodOffset) { + return Optional.of(new PatchedWordConstant(word, metaAccess.lookupJavaType(object.getClass()))); + } return Optional.of(JavaConstant.forIntegerKind(ConfigurationValues.getWordKind(), word.rawValue())); } return Optional.empty(); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/AnalysisToHostedGraphTransplanter.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/AnalysisToHostedGraphTransplanter.java index 3bef0d99b08c..22837011f519 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/AnalysisToHostedGraphTransplanter.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/AnalysisToHostedGraphTransplanter.java @@ -39,7 +39,9 @@ import com.oracle.svm.core.graal.nodes.ComputedIndirectCallTargetNode; import com.oracle.svm.core.graal.nodes.SubstrateFieldLocationIdentity; import com.oracle.svm.core.graal.nodes.SubstrateNarrowOopStamp; +import com.oracle.svm.core.meta.MethodOffset; import com.oracle.svm.core.meta.MethodPointer; +import com.oracle.svm.core.meta.SubstrateMethodOffsetConstant; import com.oracle.svm.core.meta.SubstrateMethodPointerConstant; import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.meta.HostedField; @@ -329,6 +331,13 @@ static Object replaceAnalysisObjects(Object obj, Node node, IdentityHashMap[] parameterTypes = IntStream.range(0, ref.getParameterNames().size()) .mapToObj(j -> ref.getParameterNames().get(j).toString()) .map(this::lookupBaseLayerTypeInHostVM).toArray(Class[]::new); - values[i] = new RelocatableConstant(new CEntryPointLiteralCodePointer(definingClass, methodName, parameterTypes), cEntryPointerLiteralPointerType); + values[i] = new PatchedWordConstant(new CEntryPointLiteralCodePointer(definingClass, methodName, parameterTypes), cEntryPointerLiteralPointerType); return true; } else if (constantRef.isCGlobalDataBasePointer()) { values[i] = new AnalysisFuture<>(() -> { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SVMImageLayerWriter.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SVMImageLayerWriter.java index ccca4e45bf69..2bd43a698b37 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SVMImageLayerWriter.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SVMImageLayerWriter.java @@ -73,8 +73,8 @@ import org.graalvm.collections.MapCursor; import org.graalvm.nativeimage.AnnotationAccess; import org.graalvm.nativeimage.ImageSingletons; -import org.graalvm.nativeimage.c.function.RelocatedPointer; import org.graalvm.nativeimage.impl.CEntryPointLiteralCodePointer; +import org.graalvm.word.WordBase; import com.oracle.graal.pointsto.BigBang; import com.oracle.graal.pointsto.api.HostVM; @@ -145,7 +145,7 @@ import com.oracle.svm.hosted.meta.HostedField; import com.oracle.svm.hosted.meta.HostedMethod; import com.oracle.svm.hosted.meta.HostedUniverse; -import com.oracle.svm.hosted.meta.RelocatableConstant; +import com.oracle.svm.hosted.meta.PatchedWordConstant; import com.oracle.svm.hosted.methodhandles.MethodHandleFeature; import com.oracle.svm.hosted.methodhandles.MethodHandleInvokerSubstitutionType; import com.oracle.svm.hosted.reflect.ReflectionExpandSignatureMethod; @@ -971,13 +971,13 @@ private boolean maybeWriteConstant(JavaConstant constant, ConstantReference.Buil } private static boolean delegateProcessing(ConstantReference.Builder builder, Object constant) { - if (constant instanceof RelocatableConstant relocatableConstant) { - RelocatedPointer pointer = relocatableConstant.getPointer(); - if (pointer instanceof MethodPointer methodPointer) { + if (constant instanceof PatchedWordConstant patchedWordConstant) { + WordBase word = patchedWordConstant.getWord(); + if (word instanceof MethodPointer methodPointer) { AnalysisMethod method = getRelocatableConstantMethod(methodPointer); builder.initMethodPointer().setMethodId(method.getId()); return true; - } else if (pointer instanceof CEntryPointLiteralCodePointer cp) { + } else if (word instanceof CEntryPointLiteralCodePointer cp) { CEntryPointLiteralReference.Builder b = builder.initCEntryPointLiteralCodePointer(); b.setMethodName(cp.methodName); b.setDefiningClass(cp.definingClass.getName()); @@ -986,7 +986,7 @@ private static boolean delegateProcessing(ConstantReference.Builder builder, Obj b.getParameterNames().set(i, new Text.Reader(cp.parameterTypes[i].getName())); } return true; - } else if (pointer instanceof CGlobalDataBasePointer) { + } else if (word instanceof CGlobalDataBasePointer) { builder.setCGlobalDataBasePointer(Void.VOID); return true; } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jni/JNIAccessFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jni/JNIAccessFeature.java index 24ab5ff9f788..ac4291cdef5f 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jni/JNIAccessFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jni/JNIAccessFeature.java @@ -69,7 +69,6 @@ import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.config.ObjectLayout; import com.oracle.svm.core.configure.ConfigurationFiles; -import com.oracle.svm.core.graal.meta.KnownOffsets; import com.oracle.svm.core.jni.CallVariant; import com.oracle.svm.core.jni.JNIJavaCallTrampolineHolder; import com.oracle.svm.core.jni.access.JNIAccessibleClass; @@ -609,17 +608,16 @@ private static void finishMethodBeforeCompilation(JNICallableJavaMethod method, HostedUniverse hUniverse = access.getUniverse(); AnalysisUniverse aUniverse = access.getUniverse().getBigBang().getUniverse(); HostedMethod hTarget = hUniverse.lookup(aUniverse.lookup(method.targetMethod)); - int vtableOffset; + int vtableIndex; int interfaceTypeID; if (isStaticallyBound(hTarget)) { - vtableOffset = JNIAccessibleMethod.STATICALLY_BOUND_METHOD; + vtableIndex = JNIAccessibleMethod.VTABLE_INDEX_STATICALLY_BOUND_METHOD; interfaceTypeID = JNIAccessibleMethod.INTERFACE_TYPEID_UNNEEDED; } else { + vtableIndex = hTarget.getVTableIndex(); if (SubstrateOptions.useClosedTypeWorldHubLayout()) { - vtableOffset = KnownOffsets.singleton().getVTableOffset(hTarget.getVTableIndex(), true); interfaceTypeID = JNIAccessibleMethod.INTERFACE_TYPEID_UNNEEDED; } else { - vtableOffset = KnownOffsets.singleton().getVTableOffset(hTarget.getVTableIndex(), false); HostedType declaringClass = hTarget.getDeclaringClass(); interfaceTypeID = declaringClass.isInterface() ? declaringClass.getTypeID() : JNIAccessibleMethod.INTERFACE_TYPEID_CLASS_TABLE; } @@ -630,7 +628,7 @@ private static void finishMethodBeforeCompilation(JNICallableJavaMethod method, newObjectTarget = new MethodPointer(hUniverse.lookup(aUniverse.lookup(method.newObjectMethod))); } else if (method.targetMethod.isConstructor()) { assert method.targetMethod.getDeclaringClass().isAbstract(); - newObjectTarget = Word.signed(JNIAccessibleMethod.NEW_OBJECT_INVALID_FOR_ABSTRACT_TYPE); + newObjectTarget = Word.signed(JNIAccessibleMethod.NEW_OBJECT_TARGET_INVALID_FOR_ABSTRACT_TYPE); } CodePointer callWrapper = new MethodPointer(hUniverse.lookup(aUniverse.lookup(method.callWrapper))); CodePointer varargs = new MethodPointer(hUniverse.lookup(aUniverse.lookup(method.variantWrappers.varargs))); @@ -645,7 +643,7 @@ private static void finishMethodBeforeCompilation(JNICallableJavaMethod method, valistNonvirtual = new MethodPointer(hUniverse.lookup(aUniverse.lookup(method.nonvirtualVariantWrappers.valist))); } EconomicSet> hidingSubclasses = findHidingSubclasses(hTarget.getDeclaringClass(), sub -> anyMethodMatchesIgnoreReturnType(sub, method.descriptor)); - method.jniMethod.finishBeforeCompilation(hidingSubclasses, vtableOffset, interfaceTypeID, nonvirtualTarget, newObjectTarget, callWrapper, + method.jniMethod.finishBeforeCompilation(hidingSubclasses, vtableIndex, interfaceTypeID, nonvirtualTarget, newObjectTarget, callWrapper, varargs, array, valist, varargsNonvirtual, arrayNonvirtual, valistNonvirtual); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jni/JNIJavaCallWrapperMethod.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jni/JNIJavaCallWrapperMethod.java index 742bb0255e90..837a586856e9 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jni/JNIJavaCallWrapperMethod.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jni/JNIJavaCallWrapperMethod.java @@ -246,7 +246,7 @@ private static ValueNode createMethodCallWithReceiver(JNIGraphKit kit, ResolvedS } private static ValueNode createNewObjectCall(JNIGraphKit kit, ResolvedSignature invokeSignature, ValueNode newObjectAddress, ValueNode[] args) { - ConstantNode abstractTypeSentinel = kit.createWord(JNIAccessibleMethod.NEW_OBJECT_INVALID_FOR_ABSTRACT_TYPE); + ConstantNode abstractTypeSentinel = kit.createWord(JNIAccessibleMethod.NEW_OBJECT_TARGET_INVALID_FOR_ABSTRACT_TYPE); kit.startIf(IntegerEqualsNode.create(newObjectAddress, abstractTypeSentinel, NodeView.DEFAULT), BranchProbabilityNode.SLOW_PATH_PROFILE); kit.thenPart(); var exceptionCtor = kit.getMetaAccess().lookupJavaMethod(INSTANTIATION_EXCEPTION_CONSTRUCTOR); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/RelocatableConstant.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/PatchedWordConstant.java similarity index 73% rename from substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/RelocatableConstant.java rename to substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/PatchedWordConstant.java index 6e7295ff8a94..0d82451e2ccb 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/RelocatableConstant.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/PatchedWordConstant.java @@ -25,27 +25,35 @@ package com.oracle.svm.hosted.meta; import org.graalvm.nativeimage.c.function.RelocatedPointer; +import org.graalvm.word.WordBase; import com.oracle.graal.pointsto.heap.TypedConstant; import com.oracle.graal.pointsto.meta.AnalysisType; +import com.oracle.svm.core.meta.MethodOffset; import com.oracle.svm.core.meta.MethodPointer; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; -/** Wraps pointers that are subject to relocation, so their value is not known during analysis. */ -public class RelocatableConstant implements JavaConstant, TypedConstant { +/** + * Wraps words for which the value is not known during analysis. + * + * Such words can be offsets such as {@link MethodOffset} that are patched later when the image is + * written, or {@linkplain RelocatedPointer relocated pointers} for which linker relocations are + * created. + */ +public class PatchedWordConstant implements JavaConstant, TypedConstant { - private final RelocatedPointer pointer; + private final WordBase word; private final AnalysisType type; - public RelocatableConstant(RelocatedPointer pointer, AnalysisType type) { - this.pointer = pointer; + public PatchedWordConstant(WordBase word, AnalysisType type) { + this.word = word; this.type = type; } - public RelocatedPointer getPointer() { - return pointer; + public WordBase getWord() { + return word; } @Override @@ -100,22 +108,24 @@ public AnalysisType getType() { @Override public int hashCode() { - return pointer.hashCode(); + return word.hashCode(); } @Override public boolean equals(Object obj) { - if (obj instanceof RelocatableConstant rc) { - return pointer == rc.pointer; + if (obj instanceof PatchedWordConstant rc) { + return word == rc.word; } return false; } @Override public String toValueString() { - if (pointer instanceof MethodPointer mp) { - return "relocatable method pointer: " + mp.getMethod().format("%H.%n(%p)") + ", isAbsolute: " + mp.isAbsolute(); + if (word instanceof MethodPointer mp) { + return "relocatable method pointer: " + mp.getMethod().format("%H.%n(%p)") + ", permitsRewriteToPLT: " + mp.permitsRewriteToPLT(); + } else if (word instanceof MethodOffset mo) { + return "method offset: " + mo.getMethod().format("%H.%n(%p)"); } - return "relocatable constant"; + return "patched word constant"; } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/SharedConstantFieldProvider.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/SharedConstantFieldProvider.java index 25eab0bf37f2..add18dc9504d 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/SharedConstantFieldProvider.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/SharedConstantFieldProvider.java @@ -31,6 +31,7 @@ import com.oracle.graal.pointsto.infrastructure.UniverseMetaAccess; import com.oracle.graal.pointsto.meta.AnalysisField; import com.oracle.svm.core.graal.code.CGlobalDataBasePointer; +import com.oracle.svm.core.meta.MethodOffset; import com.oracle.svm.core.meta.MethodPointer; import com.oracle.svm.hosted.SVMHost; import com.oracle.svm.hosted.ameta.FieldValueInterceptionSupport; @@ -122,10 +123,11 @@ protected boolean isClassInitialized(ResolvedJavaField field) { @Override protected boolean isFinalFieldValueConstant(ResolvedJavaField field, JavaConstant value, ConstantFieldTool tool) { - if (value.getJavaKind() == JavaKind.Object && (metaAccess.isInstanceOf(value, MethodPointer.class) || metaAccess.isInstanceOf(value, CGlobalDataBasePointer.class))) { + if (value.getJavaKind() == JavaKind.Object && (metaAccess.isInstanceOf(value, MethodPointer.class) || + metaAccess.isInstanceOf(value, MethodOffset.class) || metaAccess.isInstanceOf(value, CGlobalDataBasePointer.class))) { /* - * Prevent the constant folding of RelocatablePointer placeholder objects. These are - * "hosted" types and so cannot be present in compiler graphs. + * Prevent constant folding of placeholder objects for patched words (such as relocated + * pointers). These are "hosted" types and so cannot be present in compiler graphs. */ return false; } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/UniverseBuilder.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/UniverseBuilder.java index 6268516f4d4f..c7251c740b8b 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/UniverseBuilder.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/UniverseBuilder.java @@ -49,7 +49,7 @@ import org.graalvm.nativeimage.Platforms; import org.graalvm.nativeimage.c.function.CEntryPointLiteral; import org.graalvm.nativeimage.c.function.CFunction; -import org.graalvm.nativeimage.c.function.CFunctionPointer; +import org.graalvm.word.WordBase; import com.oracle.graal.pointsto.BigBang; import com.oracle.graal.pointsto.constraints.UnsupportedFeatures; @@ -89,6 +89,7 @@ import com.oracle.svm.core.imagelayer.DynamicImageLayerInfo; import com.oracle.svm.core.imagelayer.ImageLayerBuildingSupport; import com.oracle.svm.core.layeredimagesingleton.MultiLayeredImageSingleton; +import com.oracle.svm.core.meta.MethodOffset; import com.oracle.svm.core.meta.MethodPointer; import com.oracle.svm.core.reflect.SubstrateConstructorAccessor; import com.oracle.svm.core.reflect.SubstrateMethodAccessor; @@ -120,8 +121,9 @@ import jdk.vm.ci.meta.UnresolvedJavaType; public class UniverseBuilder { + @Platforms(Platform.HOSTED_ONLY.class) // + private static final WordBase[] EMPTY_VTABLE = new WordBase[0]; - @Platforms(Platform.HOSTED_ONLY.class) private static final CFunctionPointer[] EMPTY_ARRAY = new CFunctionPointer[0]; private final AnalysisUniverse aUniverse; private final AnalysisMetaAccess aMetaAccess; private final HostedUniverse hUniverse; @@ -957,14 +959,7 @@ private void buildHubs() { hub.setSharedData(layoutHelper, monitorOffset, identityHashOffset, referenceMapIndex, type.isInstantiated()); if (SubstrateOptions.useClosedTypeWorldHubLayout()) { - CFunctionPointer[] vtable = type.closedTypeWorldVTable.length == 0 ? EMPTY_ARRAY : new CFunctionPointer[type.closedTypeWorldVTable.length]; - for (int idx = 0; idx < type.closedTypeWorldVTable.length; idx++) { - /* - * We install a CodePointer in the vtable; when generating relocation info, we - * will know these point into .text - */ - vtable[idx] = new MethodPointer(type.closedTypeWorldVTable[idx]); - } + WordBase[] vtable = createVTable(type.closedTypeWorldVTable); hub.setClosedTypeWorldData(vtable, type.getTypeID(), type.getTypeCheckStart(), type.getTypeCheckRange(), type.getTypeCheckSlot(), type.getClosedTypeWorldTypeCheckSlots()); } else { @@ -996,19 +991,30 @@ private void buildHubs() { typeSlotIdx += 2; } - CFunctionPointer[] vtable = type.openTypeWorldDispatchTables.length == 0 ? EMPTY_ARRAY : new CFunctionPointer[type.openTypeWorldDispatchTables.length]; - for (int idx = 0; idx < type.openTypeWorldDispatchTables.length; idx++) { - /* - * We install a CodePointer in the open world vtable; when generating relocation - * info, we will know these point into .text - */ - vtable[idx] = new MethodPointer(type.openTypeWorldDispatchTables[idx]); - } + WordBase[] vtable = createVTable(type.openTypeWorldDispatchTables); + hub.setOpenTypeWorldData(vtable, type.getTypeID(), type.getTypeIDDepth(), type.getNumClassTypes(), type.getNumInterfaceTypes(), openTypeWorldTypeCheckSlots); + } + } + } - hub.setOpenTypeWorldData(vtable, type.getTypeID(), - type.getTypeIDDepth(), type.getNumClassTypes(), type.getNumInterfaceTypes(), openTypeWorldTypeCheckSlots); + private static WordBase[] createVTable(HostedMethod[] methods) { + if (methods.length == 0) { + return EMPTY_VTABLE; + } + WordBase[] vtable = new WordBase[methods.length]; + for (int i = 0; i < methods.length; i++) { + HostedMethod method = methods[i]; + if (SubstrateOptions.useRelativeCodePointers()) { + vtable[i] = new MethodOffset(method); + } else { + /* + * We install a CodePointer in the vtable; when generating relocation info, we will + * know these point into .text + */ + vtable[i] = new MethodPointer(method); } } + return vtable; } private static ReferenceMapEncoder.Input createReferenceMap(HostedType type) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/nodes/ReadReservedRegister.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/nodes/ReadReservedRegister.java index ada5c0997afa..f3882cd39969 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/nodes/ReadReservedRegister.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/nodes/ReadReservedRegister.java @@ -47,6 +47,10 @@ public static ValueNode createReadHeapBaseNode(StructuredGraph graph) { return createReadNode(graph, ReservedRegisters.singleton().getHeapBaseRegister()); } + public static ValueNode createReadCodeBaseNode(StructuredGraph graph) { + return createReadNode(graph, ReservedRegisters.singleton().getCodeBaseRegister()); + } + private static ValueNode createReadNode(StructuredGraph graph, Register register) { /* * A floating node to access the register is more efficient: it allows value numbering of diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/pltgot/IdentityMethodAddressResolverFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/pltgot/IdentityMethodAddressResolverFeature.java index 8ccdc3c026d6..4612ae818ff3 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/pltgot/IdentityMethodAddressResolverFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/pltgot/IdentityMethodAddressResolverFeature.java @@ -133,7 +133,7 @@ public void augmentImageObjectFile(ObjectFile imageObjectFile) { ObjectFile.RelocationKind relocationKind = ObjectFile.RelocationKind.getDirect(wordSize); for (int gotEntryNo = 0; gotEntryNo < got.length; ++gotEntryNo) { - offsetsSectionBuffer.addRelocationWithoutAddend(gotEntryNo * wordSize, relocationKind, new MethodPointer(got[gotEntryNo], true)); + offsetsSectionBuffer.addRelocationWithoutAddend(gotEntryNo * wordSize, relocationKind, new MethodPointer(got[gotEntryNo], false)); } imageObjectFile.createDefinedSymbol(offsetsSection.getName(), offsetsSection, 0, 0, false, false); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/pltgot/PLTGOTPointerRelocationProvider.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/pltgot/PLTGOTPointerRelocationProvider.java index df3eb86848f5..d3ea4f20d12b 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/pltgot/PLTGOTPointerRelocationProvider.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/pltgot/PLTGOTPointerRelocationProvider.java @@ -48,15 +48,10 @@ public PLTGOTPointerRelocationProvider(Predicate shouldMarkRelocat this.pltSectionSupport = HostedPLTGOTConfiguration.singleton().getPLTSectionSupport(); } - private boolean hasPLTStub(HostedMethod target, boolean isStaticallyResolved) { - return !isStaticallyResolved && shouldMarkRelocationToPLTStub.test(target); - } - @Override public void markMethodPointerRelocation(ObjectFile.ProgbitsSectionImpl section, int offset, ObjectFile.RelocationKind relocationKind, HostedMethod target, long addend, MethodPointer methodPointer, boolean isInjectedNotCompiled) { - boolean isStaticallyResolved = methodPointer.isAbsolute(); - if (hasPLTStub(target, isStaticallyResolved)) { + if (methodPointer.permitsRewriteToPLT() && shouldMarkRelocationToPLTStub.test(target)) { pltSectionSupport.markRelocationToPLTStub(section, offset, relocationKind, target, addend); } else { super.markMethodPointerRelocation(section, offset, relocationKind, target, addend, methodPointer, isInjectedNotCompiled); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionFeature.java index 0c2ef3583140..4b1fef0101d4 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionFeature.java @@ -52,17 +52,16 @@ import com.oracle.graal.pointsto.infrastructure.UniverseMetaAccess; import com.oracle.graal.pointsto.meta.AnalysisMethod; import com.oracle.graal.pointsto.meta.AnalysisUniverse; +import com.oracle.svm.configure.ConfigurationFile; +import com.oracle.svm.configure.ReflectionConfigurationParser; import com.oracle.svm.core.BuildPhaseProvider; import com.oracle.svm.core.ParsingReason; import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.annotate.Delete; -import com.oracle.svm.configure.ConfigurationFile; import com.oracle.svm.core.configure.ConfigurationFiles; -import com.oracle.svm.configure.ReflectionConfigurationParser; import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; import com.oracle.svm.core.feature.InternalFeature; import com.oracle.svm.core.fieldvaluetransformer.FieldValueTransformerWithAvailability; -import com.oracle.svm.core.graal.meta.KnownOffsets; import com.oracle.svm.core.hub.ClassForNameSupport; import com.oracle.svm.core.hub.ClassForNameSupportFeature; import com.oracle.svm.core.hub.DynamicHub; @@ -188,7 +187,7 @@ private SubstrateAccessor createAccessor(AccessorKey key) { AnalysisMethod targetMethod = null; DynamicHub initializeBeforeInvoke = null; if (member instanceof Method) { - int vtableOffset = SubstrateMethodAccessor.STATICALLY_BOUND; + int vtableIndex = SubstrateMethodAccessor.VTABLE_INDEX_STATICALLY_BOUND; Class receiverType = null; boolean callerSensitiveAdapter = false; @@ -211,18 +210,18 @@ private SubstrateAccessor createAccessor(AccessorKey key) { /* * The SubstrateMethodAccessor is also used for the implementation of MethodHandle * that are created to do an invokespecial. So non-abstract instance methods have - * both a directTarget and a vtableOffset. + * both a directTarget and a vtableIndex. */ if (!targetMethod.isAbstract()) { directTarget = asMethodPointer(targetMethod); } if (!targetMethod.canBeStaticallyBound()) { - vtableOffset = SubstrateMethodAccessor.OFFSET_NOT_YET_COMPUTED; + vtableIndex = SubstrateMethodAccessor.VTABLE_INDEX_NOT_YET_COMPUTED; } if (callerSensitiveAdapter) { - VMError.guarantee(vtableOffset == SubstrateMethodAccessor.STATICALLY_BOUND, "Caller sensitive adapters should always be statically bound %s", targetMethod); + VMError.guarantee(vtableIndex == SubstrateMethodAccessor.VTABLE_INDEX_STATICALLY_BOUND, "Caller sensitive adapters should always be statically bound %s", targetMethod); } - VMError.guarantee(directTarget != null || vtableOffset != SubstrateMethodAccessor.STATICALLY_BOUND, "Must have either a directTarget or a vtableOffset"); + VMError.guarantee(directTarget != null || vtableIndex != SubstrateMethodAccessor.VTABLE_INDEX_STATICALLY_BOUND, "Must have either a directTarget or a vtableIndex"); if (!targetMethod.isStatic()) { receiverType = target.getDeclaringClass(); } @@ -230,7 +229,7 @@ private SubstrateAccessor createAccessor(AccessorKey key) { initializeBeforeInvoke = analysisAccess.getHostVM().dynamicHub(targetMethod.getDeclaringClass()); } } - return new SubstrateMethodAccessor(member, receiverType, expandSignature, directTarget, targetMethod, vtableOffset, initializeBeforeInvoke, callerSensitiveAdapter); + return new SubstrateMethodAccessor(member, receiverType, expandSignature, directTarget, targetMethod, vtableIndex, initializeBeforeInvoke, callerSensitiveAdapter); } else { Class holder = targetClass; @@ -328,7 +327,7 @@ private static void onAccessorReachable(DuringAnalysisAccess a, SubstrateAccesso access.registerAsRoot((AnalysisMethod) targetMethod, true, reason); } /* If the accessor can be used for a virtual call, register virtual root method. */ - if (accessor instanceof SubstrateMethodAccessor mAccessor && mAccessor.getVTableOffset() != SubstrateMethodAccessor.STATICALLY_BOUND) { + if (accessor instanceof SubstrateMethodAccessor mAccessor && mAccessor.getVTableIndex() != SubstrateMethodAccessor.VTABLE_INDEX_STATICALLY_BOUND) { access.registerAsRoot((AnalysisMethod) targetMethod, false, reason); } /* Register constructor factory method */ @@ -347,13 +346,11 @@ public void beforeAnalysis(BeforeAnalysisAccess access) { reflectionData.setAnalysisAccess(access); /* - * This has to be registered before registering methods below since this causes the analysis - * to see SubstrateMethodAccessor.vtableOffset before we register the transformer. + * These transformers have to be registered before registering methods below which causes + * the analysis to already see SubstrateMethodAccessor.vtableIndex. */ - access.registerFieldValueTransformer(ReflectionUtil.lookupField(SubstrateMethodAccessor.class, "vtableOffset"), new ComputeVTableOffset()); - if (!SubstrateOptions.useClosedTypeWorldHubLayout()) { - access.registerFieldValueTransformer(ReflectionUtil.lookupField(SubstrateMethodAccessor.class, "interfaceTypeID"), new ComputeInterfaceTypeID()); - } + access.registerFieldValueTransformer(ReflectionUtil.lookupField(SubstrateMethodAccessor.class, "vtableIndex"), new ComputeVTableIndex()); + access.registerFieldValueTransformer(ReflectionUtil.lookupField(SubstrateMethodAccessor.class, "interfaceTypeID"), new ComputeInterfaceTypeID()); /* Make sure array classes don't need to be registered for reflection. */ RuntimeReflection.register(Object.class.getDeclaredMethods()); @@ -484,7 +481,7 @@ String uniqueShortName() { } } -final class ComputeVTableOffset implements FieldValueTransformerWithAvailability { +final class ComputeVTableIndex implements FieldValueTransformerWithAvailability { @Override public boolean isAvailable() { return BuildPhaseProvider.isHostedUniverseBuilt(); @@ -494,19 +491,15 @@ public boolean isAvailable() { public Object transform(Object receiver, Object originalValue) { SubstrateMethodAccessor accessor = (SubstrateMethodAccessor) receiver; - if (accessor.getVTableOffset() == SubstrateMethodAccessor.OFFSET_NOT_YET_COMPUTED) { + if (accessor.getVTableIndex() == SubstrateMethodAccessor.VTABLE_INDEX_NOT_YET_COMPUTED) { HostedMethod member = ImageSingletons.lookup(ReflectionFeature.class).hostedMetaAccess().lookupJavaMethod(accessor.getMember()); if (member.canBeStaticallyBound()) { - return SubstrateMethodAccessor.STATICALLY_BOUND; - } - if (SubstrateOptions.useClosedTypeWorldHubLayout()) { - return KnownOffsets.singleton().getVTableOffset(member.getVTableIndex(), true); - } else { - return KnownOffsets.singleton().getVTableOffset(member.getVTableIndex(), false); + return SubstrateMethodAccessor.VTABLE_INDEX_STATICALLY_BOUND; } + return member.getVTableIndex(); } else { - VMError.guarantee(accessor.getVTableOffset() == SubstrateMethodAccessor.STATICALLY_BOUND); - return accessor.getVTableOffset(); + VMError.guarantee(accessor.getVTableIndex() == SubstrateMethodAccessor.VTABLE_INDEX_STATICALLY_BOUND); + return accessor.getVTableIndex(); } } } @@ -520,7 +513,10 @@ public boolean isAvailable() { @Override public Object transform(Object receiver, Object originalValue) { SubstrateMethodAccessor accessor = (SubstrateMethodAccessor) receiver; - VMError.guarantee(accessor.getInterfaceTypeID() == SubstrateMethodAccessor.OFFSET_NOT_YET_COMPUTED); + VMError.guarantee(accessor.getInterfaceTypeID() == SubstrateMethodAccessor.INTERFACE_TYPEID_NOT_YET_COMPUTED); + if (SubstrateOptions.useClosedTypeWorldHubLayout()) { + return SubstrateMethodAccessor.INTERFACE_TYPEID_UNNEEDED; + } HostedMethod member = ImageSingletons.lookup(ReflectionFeature.class).hostedMetaAccess().lookupJavaMethod(accessor.getMember()); if (member.getDeclaringClass().isInterface()) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/SubstrateGraphBuilderPlugins.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/SubstrateGraphBuilderPlugins.java index e371cedcc9ed..31db4513a902 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/SubstrateGraphBuilderPlugins.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/SubstrateGraphBuilderPlugins.java @@ -932,6 +932,13 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec return true; } }); + r.register(new RequiredInvocationPlugin("codeBase") { + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { + b.addPush(JavaKind.Object, ReadReservedRegister.createReadCodeBaseNode(b.getGraph())); + return true; + } + }); r.register(new RequiredInvocationPlugin("readHub", Object.class) { @Override public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode object) { diff --git a/substratevm/src/com.oracle.svm.interpreter/src/com/oracle/svm/interpreter/InterpreterToVM.java b/substratevm/src/com.oracle.svm.interpreter/src/com/oracle/svm/interpreter/InterpreterToVM.java index 7f24eb467646..ff8f674cfa9e 100644 --- a/substratevm/src/com.oracle.svm.interpreter/src/com/oracle/svm/interpreter/InterpreterToVM.java +++ b/substratevm/src/com.oracle.svm.interpreter/src/com/oracle/svm/interpreter/InterpreterToVM.java @@ -37,6 +37,7 @@ import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.MissingReflectionRegistrationError; import org.graalvm.nativeimage.c.function.CFunctionPointer; +import org.graalvm.word.UnsignedWord; import org.graalvm.word.WordBase; import com.oracle.svm.core.SubstrateOptions; @@ -49,6 +50,7 @@ import com.oracle.svm.core.jdk.InternalVMMethod; import com.oracle.svm.core.monitor.MonitorInflationCause; import com.oracle.svm.core.monitor.MonitorSupport; +import com.oracle.svm.core.snippets.KnownIntrinsics; import com.oracle.svm.core.util.VMError; import com.oracle.svm.interpreter.metadata.InterpreterResolvedJavaField; import com.oracle.svm.interpreter.metadata.InterpreterResolvedJavaMethod; @@ -691,7 +693,16 @@ static CFunctionPointer peekAtSVMVTable(Class seedClass, Class thisClass, vtableOffset += (int) OpenTypeWorldDispatchTableSnippets.determineITableStartingOffset(thisHub, seedHub.getTypeID()); } } - return Word.objectToTrackedPointer(thisHub).readWord(vtableOffset); + WordBase vtableEntry = Word.objectToTrackedPointer(thisHub).readWord(vtableOffset); + return getSVMVTableCodePointer(vtableEntry); + } + + private static CFunctionPointer getSVMVTableCodePointer(WordBase vtableEntry) { + WordBase codePointer = vtableEntry; + if (SubstrateOptions.useRelativeCodePointers()) { + codePointer = KnownIntrinsics.codeBase().add((UnsignedWord) codePointer); + } + return (CFunctionPointer) codePointer; } private static InterpreterResolvedJavaMethod peekAtInterpreterVTable(Class seedClass, Class thisClass, int vTableIndex, boolean isInvokeInterface) { diff --git a/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/WebImageFeature.java b/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/WebImageFeature.java index f1cd1e1848a8..9140cff138b5 100644 --- a/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/WebImageFeature.java +++ b/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/WebImageFeature.java @@ -33,6 +33,8 @@ import java.nio.file.Path; import java.util.ArrayList; import java.util.List; +import java.util.Map; +import java.util.function.Predicate; import java.util.function.Supplier; import org.graalvm.nativeimage.AnnotationAccess; @@ -61,7 +63,10 @@ import com.oracle.svm.core.code.ImageCodeInfo; import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; import com.oracle.svm.core.feature.InternalFeature; +import com.oracle.svm.core.graal.meta.RuntimeConfiguration; import com.oracle.svm.core.graal.meta.SubstrateForeignCallsProvider; +import com.oracle.svm.core.graal.snippets.NodeLoweringProvider; +import com.oracle.svm.core.heap.RestrictHeapAccessCallees; import com.oracle.svm.core.hub.DynamicHub; import com.oracle.svm.core.hub.DynamicHubCompanion; import com.oracle.svm.core.jdk.FileSystemProviderSupport; @@ -83,6 +88,7 @@ import com.oracle.svm.hosted.webimage.codegen.WebImageProviders; import com.oracle.svm.hosted.webimage.name.WebImageNamingConvention; import com.oracle.svm.hosted.webimage.options.WebImageOptions; +import com.oracle.svm.hosted.webimage.snippets.WebImageNonSnippetLowerings; import com.oracle.svm.hosted.webimage.wasm.WasmLogHandler; import com.oracle.svm.util.ReflectionUtil; import com.oracle.svm.webimage.WebImageJSLog; @@ -103,8 +109,11 @@ import com.oracle.svm.webimage.substitute.system.WebImageTempFileHelperSupportWithoutSecureRandom; import jdk.graal.compiler.debug.DebugContext; +import jdk.graal.compiler.graph.Node; import jdk.graal.compiler.options.OptionValues; +import jdk.graal.compiler.phases.util.Providers; import jdk.graal.compiler.serviceprovider.JavaVersionUtil; +import jdk.vm.ci.meta.ResolvedJavaMethod; @AutomaticallyRegisteredFeature @Platforms(WebImagePlatform.class) @@ -123,6 +132,16 @@ public void registerForeignCalls(SubstrateForeignCallsProvider foreignCalls) { ImplicitExceptions.registerForeignCalls(foreignCalls); } + @Override + public void registerLowerings(RuntimeConfiguration runtimeConfig, OptionValues options, Providers providers, Map, NodeLoweringProvider> lowerings, boolean hosted) { + Predicate mustNotAllocatePredicate = null; + if (hosted) { + mustNotAllocatePredicate = method -> ImageSingletons.lookup(RestrictHeapAccessCallees.class).mustNotAllocate(method); + } + + WebImageNonSnippetLowerings.registerLowerings(runtimeConfig, mustNotAllocatePredicate, options, providers, lowerings, hosted); + } + @Override public void beforeAnalysis(BeforeAnalysisAccess access) { FeatureImpl.BeforeAnalysisAccessImpl accessImpl = (FeatureImpl.BeforeAnalysisAccessImpl) access; diff --git a/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/codegen/WebImageJSNodeLowerer.java b/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/codegen/WebImageJSNodeLowerer.java index f9a272c6f988..451e141a0724 100644 --- a/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/codegen/WebImageJSNodeLowerer.java +++ b/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/codegen/WebImageJSNodeLowerer.java @@ -44,6 +44,7 @@ import com.oracle.svm.core.classinitialization.EnsureClassInitializedNode; import com.oracle.svm.core.genscavenge.graal.nodes.FormatArrayNode; import com.oracle.svm.core.genscavenge.graal.nodes.FormatObjectNode; +import com.oracle.svm.core.graal.nodes.FloatingWordCastNode; import com.oracle.svm.core.graal.nodes.LoweredDeadEndNode; import com.oracle.svm.core.graal.nodes.ReadCallerStackPointerNode; import com.oracle.svm.core.graal.nodes.ReadReturnAddressNode; @@ -334,6 +335,8 @@ protected void dispatch(Node node) { lower(readIdentityHashCodeNode); } else if (node instanceof WriteIdentityHashCodeNode writeIdentityHashCodeNode) { lower(writeIdentityHashCodeNode); + } else if (node instanceof FloatingWordCastNode floatingWordCastNode) { + lower(floatingWordCastNode); } else { super.dispatch(node); } @@ -968,6 +971,10 @@ protected void lower(WordCastNode node) { lowerValue(node.getInput()); } + protected void lower(FloatingWordCastNode node) { + lowerValue(node.getInput()); + } + @Override protected void lower(InstanceOfNode node) { CodeBuffer masm = codeGenTool.getCodeBuffer(); diff --git a/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/codegen/heap/WebImageObjectInspector.java b/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/codegen/heap/WebImageObjectInspector.java index 3cb2164c5baa..9b44b8db3c67 100644 --- a/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/codegen/heap/WebImageObjectInspector.java +++ b/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/codegen/heap/WebImageObjectInspector.java @@ -38,7 +38,7 @@ import com.oracle.svm.hosted.meta.HostedField; import com.oracle.svm.hosted.meta.HostedType; import com.oracle.svm.hosted.meta.HostedUniverse; -import com.oracle.svm.hosted.meta.RelocatableConstant; +import com.oracle.svm.hosted.meta.PatchedWordConstant; import com.oracle.svm.hosted.webimage.codegen.WebImageJSProviders; import com.oracle.svm.hosted.webimage.codegen.WebImageTypeControl; import com.oracle.svm.webimage.object.ConstantIdentityMapping; @@ -219,7 +219,7 @@ private void buildObjectType(ObjectType out, JavaConstant c, ConstantIdentityMap members.add(inspectObject(fieldValue, out, identityMapping)); } else if (f.getType().isPrimitive() || (f.getJavaKind().isObject() && f.getType().getStorageKind().isPrimitive())) { JavaConstant fieldValue = constantReflection.readFieldValue(f, c); - if (fieldValue instanceof RelocatableConstant rc && rc.getPointer() instanceof MethodPointer pointer) { + if (fieldValue instanceof PatchedWordConstant pwc && pwc.getWord() instanceof MethodPointer pointer) { AnalysisMethod method = (AnalysisMethod) pointer.getMethod(); ResolvedJavaMethod hostedMethod = hUniverse.lookup(method); @@ -228,7 +228,7 @@ private void buildObjectType(ObjectType out, JavaConstant c, ConstantIdentityMap typeControl.requestTypeName(hostedMethod.getDeclaringClass()); int index = identityMapping.addMethodPointer(hostedMethod); - members.add(new MethodPointerType(rc, hostedMethod, index, f)); + members.add(new MethodPointerType(pwc, hostedMethod, index, f)); } else if (fieldValue instanceof PrimitiveConstant primitiveConstant) { members.add(inspectObject(primitiveConstant, out, identityMapping)); } else { diff --git a/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/js/WebImageJSLoweringProvider.java b/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/js/WebImageJSLoweringProvider.java index 3a6b4e71502b..7b552539404f 100644 --- a/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/js/WebImageJSLoweringProvider.java +++ b/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/js/WebImageJSLoweringProvider.java @@ -26,6 +26,7 @@ package com.oracle.svm.hosted.webimage.js; import com.oracle.svm.core.classinitialization.EnsureClassInitializedNode; +import com.oracle.svm.core.graal.nodes.LoadMethodByIndexNode; import com.oracle.svm.core.graal.snippets.NodeLoweringProvider; import com.oracle.svm.hosted.webimage.WebImageLoweringProvider; import com.oracle.svm.hosted.webimage.snippets.WebImageIdentityHashCodeSnippets; @@ -61,7 +62,7 @@ protected IdentityHashCodeSnippets.Templates createIdentityHashCodeSnippets(Opti @SuppressWarnings("unchecked") @Override public void lower(Node n, LoweringTool tool) { - if (n instanceof EnsureClassInitializedNode || n instanceof ValidateNewInstanceClassNode) { + if (n instanceof EnsureClassInitializedNode || n instanceof ValidateNewInstanceClassNode || n instanceof LoadMethodByIndexNode) { @SuppressWarnings("rawtypes") NodeLoweringProvider nodeLoweringProvider = getLowerings().get(n.getClass()); diff --git a/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/options/WebImageOptions.java b/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/options/WebImageOptions.java index 218eccf6e537..889a7d146399 100644 --- a/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/options/WebImageOptions.java +++ b/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/options/WebImageOptions.java @@ -126,7 +126,7 @@ public static final class DebugOptions { public static final HostedOptionKey RuntimeDebugChecks = new HostedOptionKey<>(false); @Option(help = "Enable verification phases.")// - public static final OptionKey VerificationPhases = new OptionKey<>(false); + public static final HostedOptionKey VerificationPhases = new HostedOptionKey<>(false); @Option(help = "Dump type control graph, a graph of dependencies between types, methods, and inspected objects.")// public static final OptionKey DumpTypeControlGraph = new OptionKey<>(false); diff --git a/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/wasm/snippets/WebImageWasmNonSnippetLowerings.java b/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/snippets/WebImageNonSnippetLowerings.java similarity index 83% rename from web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/wasm/snippets/WebImageWasmNonSnippetLowerings.java rename to web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/snippets/WebImageNonSnippetLowerings.java index aa220b0131c6..debdc77c6f57 100644 --- a/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/wasm/snippets/WebImageWasmNonSnippetLowerings.java +++ b/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/snippets/WebImageNonSnippetLowerings.java @@ -23,7 +23,7 @@ * questions. */ -package com.oracle.svm.hosted.webimage.wasm.snippets; +package com.oracle.svm.hosted.webimage.snippets; import java.util.Map; import java.util.function.Predicate; @@ -37,16 +37,16 @@ import jdk.graal.compiler.phases.util.Providers; import jdk.vm.ci.meta.ResolvedJavaMethod; -public class WebImageWasmNonSnippetLowerings extends NonSnippetLowerings { +public class WebImageNonSnippetLowerings extends NonSnippetLowerings { @SuppressWarnings("unused") public static void registerLowerings(RuntimeConfiguration runtimeConfig, Predicate mustNotAllocatePredicate, OptionValues options, Providers providers, Map, NodeLoweringProvider> lowerings, boolean hosted) { - new WebImageWasmNonSnippetLowerings(runtimeConfig, mustNotAllocatePredicate, options, providers, lowerings, hosted); + new WebImageNonSnippetLowerings(runtimeConfig, mustNotAllocatePredicate, options, providers, lowerings, hosted); } - protected WebImageWasmNonSnippetLowerings(RuntimeConfiguration runtimeConfig, Predicate mustNotAllocatePredicate, OptionValues options, Providers providers, + protected WebImageNonSnippetLowerings(RuntimeConfiguration runtimeConfig, Predicate mustNotAllocatePredicate, OptionValues options, Providers providers, Map, NodeLoweringProvider> lowerings, boolean hosted) { super(runtimeConfig, mustNotAllocatePredicate, options, providers, lowerings, hosted); } diff --git a/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/wasm/WebImageWasmReservedRegisters.java b/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/wasm/WebImageWasmReservedRegisters.java index cacc6e437d71..51e9d2dcfbe4 100644 --- a/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/wasm/WebImageWasmReservedRegisters.java +++ b/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/wasm/WebImageWasmReservedRegisters.java @@ -51,6 +51,6 @@ public class WebImageWasmReservedRegisters extends ReservedRegisters { @Platforms(Platform.HOSTED_ONLY.class) protected WebImageWasmReservedRegisters() { - super(FRAME_REGISTER, null, null); + super(FRAME_REGISTER, null, null, null); } } diff --git a/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/wasm/codegen/WebImageWasmLMNodeLowerer.java b/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/wasm/codegen/WebImageWasmLMNodeLowerer.java index 8271419b6e99..10066a09a1ba 100644 --- a/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/wasm/codegen/WebImageWasmLMNodeLowerer.java +++ b/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/wasm/codegen/WebImageWasmLMNodeLowerer.java @@ -41,6 +41,7 @@ import static com.oracle.svm.webimage.functionintrinsics.JSCallNode.MEM_FREE; import static com.oracle.svm.webimage.functionintrinsics.JSCallNode.MEM_MALLOC; import static com.oracle.svm.webimage.functionintrinsics.JSCallNode.MEM_REALLOC; +import static com.oracle.svm.webimage.wasm.types.WasmPrimitiveType.i64; import java.util.Set; @@ -394,10 +395,17 @@ protected Instruction lowerInvoke(T node) { callTarget.arguments().forEach(param -> params.add(lowerExpression(param))); if (callTarget instanceof IndirectCallTargetNode indirectCallTarget) { + WasmPrimitiveType addressType = util.typeForNode(indirectCallTarget.computedAddress()).asPrimitive(); + Instruction index = lowerExpression(indirectCallTarget.computedAddress()); /* - * TODO GR-42105 stop using wrap + * The computed address can have different kind of stamps that are represented as either + * i32 or i64 in wasm. For example the stamp could be an i64 integer stamp (represented + * as i64) or a method pointer stamp (represented as i32). If the computed address is + * represented as an i64, it has to first be truncated to i32. */ - Instruction index = Unary.Op.I32Wrap64.create(lowerExpression(indirectCallTarget.computedAddress())); + if (addressType == i64) { + index = Unary.Op.I32Wrap64.create(index); + } TypeUse typeUse; if (targetMethod == null) { @@ -429,40 +437,6 @@ private Instruction lowerReadReservedRegister(Register register) { } } - private Instruction lowerWordCast(WordCastNode n) { - ValueNode input = n.getInput(); - Instruction value = lowerExpression(input); - - int inputBits = util.typeForNode(input).asPrimitive().getBitCount(); - int outputBits = util.typeForNode(n).asPrimitive().getBitCount(); - - /* - * TODO GR-42105 word types are 64-bit while objects are 32-bits. Add 32-bit architecture, - * then we can probably save both the wrap and extend operations. - */ - if (inputBits == outputBits) { - return value; - } else if (inputBits == 32 && outputBits == 64) { - return Unary.Op.I64ExtendI32U.create(value); - } else if (inputBits == 64 && outputBits == 32) { - return Unary.Op.I32Wrap64.create(value); - } else { - throw GraalError.unimplemented(n + ", inputBits=" + inputBits + ", outputBits=" + outputBits); // ExcludeFromJacocoGeneratedReport - } - } - - private Instruction lowerFloatingWordCast(FloatingWordCastNode n) { - ValueNode input = n.getInput(); - - Instruction value = lowerExpression(input); - /* - * TODO GR-42105 the input is a 64-bit word type, add architecture to ensure word type is 32 - * bit and we don't need to i32.wrap64 instruction. - */ - assert input.getStackKind().getBitCount() == 64 : input.getStackKind(); - return Unary.Op.I32Wrap64.create(value); - } - private Instruction lowerWasmAddressBase(WasmAddressNode n) { ValueNode baseNode = n.getBase(); diff --git a/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/wasm/codegen/WebImageWasmNodeLowerer.java b/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/wasm/codegen/WebImageWasmNodeLowerer.java index 58b0f796ee43..c1d93995090b 100644 --- a/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/wasm/codegen/WebImageWasmNodeLowerer.java +++ b/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/wasm/codegen/WebImageWasmNodeLowerer.java @@ -39,6 +39,7 @@ import java.util.Objects; import java.util.Set; +import com.oracle.svm.core.graal.nodes.FloatingWordCastNode; import com.oracle.svm.core.graal.nodes.ReadExceptionObjectNode; import com.oracle.svm.core.meta.SubstrateMethodPointerConstant; import com.oracle.svm.core.snippets.SnippetRuntime; @@ -1144,6 +1145,35 @@ protected Instruction lowerReadException(@SuppressWarnings("unused") ReadExcepti return exceptionObjectVariable.getter(); } + protected Instruction lowerWordCast(WordCastNode n) { + return lowerWordCast(n, n.getInput()); + } + + protected Instruction lowerFloatingWordCast(FloatingWordCastNode n) { + return lowerWordCast(n, n.getInput()); + } + + protected Instruction lowerWordCast(ValueNode castNode, ValueNode input) { + Instruction value = lowerExpression(input); + + int inputBits = util.typeForNode(input).asPrimitive().getBitCount(); + int outputBits = util.typeForNode(castNode).asPrimitive().getBitCount(); + + /* + * TODO GR-42105 word types are 64-bit while objects are 32-bits. Add 32-bit architecture, + * then we can probably save both the wrap and extend operations. + */ + if (inputBits == outputBits) { + return value; + } else if (inputBits == 32 && outputBits == 64) { + return Unary.Op.I64ExtendI32U.create(value); + } else if (inputBits == 64 && outputBits == 32) { + return Unary.Op.I32Wrap64.create(value); + } else { + throw GraalError.unimplemented(castNode + ", inputBits=" + inputBits + ", outputBits=" + outputBits); // ExcludeFromJacocoGeneratedReport + } + } + // region Unsupported operations private static void genUnreachable(Object comment) { GraalError.shouldNotReachHere(String.valueOf(comment)); diff --git a/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/wasm/snippets/WasmLMSnippetsFeature.java b/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/wasm/snippets/WasmLMSnippetsFeature.java index f73cfc298af0..c62490865cbb 100644 --- a/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/wasm/snippets/WasmLMSnippetsFeature.java +++ b/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/wasm/snippets/WasmLMSnippetsFeature.java @@ -26,35 +26,24 @@ package com.oracle.svm.hosted.webimage.wasm.snippets; import java.util.Map; -import java.util.function.Predicate; -import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Platforms; import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; import com.oracle.svm.core.feature.InternalFeature; import com.oracle.svm.core.graal.meta.RuntimeConfiguration; import com.oracle.svm.core.graal.snippets.NodeLoweringProvider; -import com.oracle.svm.core.heap.RestrictHeapAccessCallees; import com.oracle.svm.webimage.platform.WebImageWasmLMPlatform; import jdk.graal.compiler.graph.Node; import jdk.graal.compiler.options.OptionValues; import jdk.graal.compiler.phases.util.Providers; -import jdk.vm.ci.meta.ResolvedJavaMethod; @AutomaticallyRegisteredFeature @Platforms(WebImageWasmLMPlatform.class) class WasmLMSnippetsFeature implements InternalFeature { - @Override public void registerLowerings(RuntimeConfiguration runtimeConfig, OptionValues options, Providers providers, Map, NodeLoweringProvider> lowerings, boolean hosted) { - Predicate mustNotAllocatePredicate = null; - if (hosted) { - mustNotAllocatePredicate = method -> ImageSingletons.lookup(RestrictHeapAccessCallees.class).mustNotAllocate(method); - } - WebImageWasmArithmeticSnippets.registerLowerings(options, providers, lowerings); - WebImageWasmNonSnippetLowerings.registerLowerings(runtimeConfig, mustNotAllocatePredicate, options, providers, lowerings, hosted); } } diff --git a/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/wasmgc/WebImageWasmGCLoweringProvider.java b/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/wasmgc/WebImageWasmGCLoweringProvider.java index ee0fef62d336..aaaa884e4c6c 100644 --- a/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/wasmgc/WebImageWasmGCLoweringProvider.java +++ b/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/wasmgc/WebImageWasmGCLoweringProvider.java @@ -32,6 +32,7 @@ import com.oracle.svm.core.classinitialization.EnsureClassInitializedNode; import com.oracle.svm.core.graal.jdk.SubstrateObjectCloneNode; import com.oracle.svm.core.graal.jdk.SubstrateObjectCloneWithExceptionNode; +import com.oracle.svm.core.graal.nodes.LoadMethodByIndexNode; import com.oracle.svm.core.graal.nodes.ThrowBytecodeExceptionNode; import com.oracle.svm.core.graal.snippets.NodeLoweringProvider; import com.oracle.svm.core.hub.DynamicHub; @@ -112,7 +113,8 @@ public WebImageWasmGCLoweringProvider(MetaAccessProvider metaAccess, ForeignCall SubstrateObjectCloneNode.class, SubstrateObjectCloneWithExceptionNode.class, IntegerDivRemNode.class, - DeoptimizeNode.class)); + DeoptimizeNode.class, + LoadMethodByIndexNode.class)); @Override public void initialize(OptionValues options, SnippetCounter.Group.Factory factory, Providers providers) { diff --git a/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/wasmgc/codegen/WasmGCHeapWriter.java b/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/wasmgc/codegen/WasmGCHeapWriter.java index 1238e0e91905..b1265797ad76 100644 --- a/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/wasmgc/codegen/WasmGCHeapWriter.java +++ b/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/wasmgc/codegen/WasmGCHeapWriter.java @@ -39,7 +39,7 @@ import java.util.function.Consumer; import java.util.stream.Stream; -import org.graalvm.nativeimage.c.function.CFunctionPointer; +import org.graalvm.word.WordBase; import com.oracle.graal.pointsto.heap.ImageHeapArray; import com.oracle.graal.pointsto.heap.ImageHeapConstant; @@ -64,7 +64,7 @@ import com.oracle.svm.hosted.meta.HostedMetaAccess; import com.oracle.svm.hosted.meta.HostedType; import com.oracle.svm.hosted.meta.MaterializedConstantFields; -import com.oracle.svm.hosted.meta.RelocatableConstant; +import com.oracle.svm.hosted.meta.PatchedWordConstant; import com.oracle.svm.hosted.webimage.WebImageCodeCache; import com.oracle.svm.hosted.webimage.wasm.WebImageWasmOptions; import com.oracle.svm.hosted.webimage.wasm.ast.ActiveElements; @@ -739,8 +739,8 @@ private Instruction getArgumentForField(ObjectInfo info, HostedField field) { */ private Instruction getArgumentForValue(JavaConstant value) { Instruction arg; - if (value instanceof RelocatableConstant relocatableConstant) { - if (relocatableConstant.getPointer() instanceof MethodPointer methodPointer) { + if (value instanceof PatchedWordConstant patchedConstant) { + if (patchedConstant.getWord() instanceof MethodPointer methodPointer) { arg = Instruction.Relocation.forConstant(new SubstrateMethodPointerConstant(methodPointer)); } else { throw VMError.shouldNotReachHere("Pointers to memory should not appear in the WasmGC image heap: " + value); @@ -835,7 +835,7 @@ private Instruction createAccessDispatchArray(List allFields, Consu private Instruction createHubVtableArray(ImageHeapInstance instance) { WasmId.ArrayType vtableFieldType = providers.knownIds().vtableFieldType; DynamicHubLayout dynamicHubLayout = DynamicHubLayout.singleton(); - CFunctionPointer[] vtable = (CFunctionPointer[]) heap.readInlinedField(dynamicHubLayout.vTableField, instance); + WordBase[] vtable = (WordBase[]) heap.readInlinedField(dynamicHubLayout.vTableField, instance); int vtableLength = vtable.length; diff --git a/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/wasmgc/codegen/WebImageWasmGCNodeLowerer.java b/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/wasmgc/codegen/WebImageWasmGCNodeLowerer.java index f7de0fe7a9d6..b5bda7a20df8 100644 --- a/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/wasmgc/codegen/WebImageWasmGCNodeLowerer.java +++ b/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/wasmgc/codegen/WebImageWasmGCNodeLowerer.java @@ -32,6 +32,7 @@ import com.oracle.graal.pointsto.infrastructure.OriginalClassProvider; import com.oracle.graal.pointsto.results.StrengthenGraphs; +import com.oracle.svm.core.graal.nodes.FloatingWordCastNode; import com.oracle.svm.core.graal.nodes.LoweredDeadEndNode; import com.oracle.svm.core.graal.nodes.ReadExceptionObjectNode; import com.oracle.svm.core.hub.DynamicHub; @@ -45,6 +46,7 @@ import com.oracle.svm.hosted.webimage.js.JSBody; import com.oracle.svm.hosted.webimage.js.JSBodyNode; import com.oracle.svm.hosted.webimage.js.JSBodyWithExceptionNode; +import com.oracle.svm.hosted.webimage.options.WebImageOptions; import com.oracle.svm.hosted.webimage.wasm.WasmJSCounterparts; import com.oracle.svm.hosted.webimage.wasm.WebImageWasmOptions; import com.oracle.svm.hosted.webimage.wasm.ast.Instruction; @@ -283,11 +285,14 @@ protected Instruction dispatch(ValueNode n, WasmIRWalker.Requirements reqs) { case JSBodyNode jsBody -> lowerJSBody(jsBody); case JSBodyWithExceptionNode jsBody -> lowerJSBody(jsBody); case WordCastNode wordCast -> lowerWordCast(wordCast); + case FloatingWordCastNode wordCast -> lowerFloatingWordCast(wordCast); default -> { assert !isForbiddenNode(n) : reportForbiddenNode(n); + if (WebImageOptions.DebugOptions.VerificationPhases.getValue()) { + throw GraalError.shouldNotReachHere("Tried to lower unknown node: " + n); + } // TODO GR-47009 Stop generating stub code. yield getStub(n); - // throw GraalError.shouldNotReachHere("Tried to lower unknown node: " + n); } }; } @@ -1078,7 +1083,8 @@ private Instruction lowerJSBody(T jsBody) { return returnValue; } - private Instruction lowerWordCast(WordCastNode n) { + @Override + protected Instruction lowerWordCast(WordCastNode n) { // TODO GR-60168 Eliminate WordCastNodes completely. They are fundamentally not supportable // under WasmGC logError("This method should never be reached and cannot be supported."); diff --git a/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/wasmgc/snippets/WasmGCSnippetsFeature.java b/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/wasmgc/snippets/WasmGCSnippetsFeature.java index 3142d4f7f17c..173c604065f1 100644 --- a/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/wasmgc/snippets/WasmGCSnippetsFeature.java +++ b/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/wasmgc/snippets/WasmGCSnippetsFeature.java @@ -26,36 +26,25 @@ package com.oracle.svm.hosted.webimage.wasmgc.snippets; import java.util.Map; -import java.util.function.Predicate; -import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Platforms; import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; import com.oracle.svm.core.feature.InternalFeature; import com.oracle.svm.core.graal.meta.RuntimeConfiguration; import com.oracle.svm.core.graal.snippets.NodeLoweringProvider; -import com.oracle.svm.core.heap.RestrictHeapAccessCallees; import com.oracle.svm.hosted.webimage.wasm.snippets.WebImageWasmArithmeticSnippets; -import com.oracle.svm.hosted.webimage.wasm.snippets.WebImageWasmNonSnippetLowerings; import com.oracle.svm.webimage.platform.WebImageWasmGCPlatform; import jdk.graal.compiler.graph.Node; import jdk.graal.compiler.options.OptionValues; import jdk.graal.compiler.phases.util.Providers; -import jdk.vm.ci.meta.ResolvedJavaMethod; @AutomaticallyRegisteredFeature @Platforms(WebImageWasmGCPlatform.class) public class WasmGCSnippetsFeature implements InternalFeature { @Override public void registerLowerings(RuntimeConfiguration runtimeConfig, OptionValues options, Providers providers, Map, NodeLoweringProvider> lowerings, boolean hosted) { - Predicate mustNotAllocatePredicate = null; - if (hosted) { - mustNotAllocatePredicate = method -> ImageSingletons.lookup(RestrictHeapAccessCallees.class).mustNotAllocate(method); - } - WebImageWasmArithmeticSnippets.registerLowerings(options, providers, lowerings); - WebImageWasmNonSnippetLowerings.registerLowerings(runtimeConfig, mustNotAllocatePredicate, options, providers, lowerings, hosted); } }