Skip to content

Commit 012ed95

Browse files
Implement jdk.vm.ci.services.Services#readSystemPropertiesInfo
1 parent 9f90763 commit 012ed95

File tree

2 files changed

+161
-2
lines changed

2 files changed

+161
-2
lines changed
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
/*
2+
* Copyright (c) 2025, 2025, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
package com.oracle.truffle.espresso.substitutions.jvmci;
24+
25+
import static com.oracle.truffle.espresso.substitutions.jvmci.Target_jdk_vm_ci_runtime_JVMCI.checkJVMCIAvailable;
26+
27+
import java.nio.ByteBuffer;
28+
import java.nio.charset.StandardCharsets;
29+
import java.util.Map;
30+
31+
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
32+
import com.oracle.truffle.api.interop.TruffleObject;
33+
import com.oracle.truffle.espresso.EspressoLanguage;
34+
import com.oracle.truffle.espresso.ffi.nfi.NativeUtils;
35+
import com.oracle.truffle.espresso.runtime.EspressoContext;
36+
import com.oracle.truffle.espresso.runtime.staticobject.StaticObject;
37+
import com.oracle.truffle.espresso.substitutions.EspressoSubstitutions;
38+
import com.oracle.truffle.espresso.substitutions.Inject;
39+
import com.oracle.truffle.espresso.substitutions.JavaType;
40+
import com.oracle.truffle.espresso.substitutions.Substitution;
41+
42+
@EspressoSubstitutions
43+
final class Target_jdk_vm_ci_services_Services {
44+
45+
private Target_jdk_vm_ci_services_Services() {
46+
}
47+
48+
private static final long NODE_STRUCT_SIZE = 8 * 3;
49+
private static final int NODE_STRUCT_KEY_OFFSET = 0;
50+
private static final int NODE_STRUCT_VALUE_OFFSET = 8;
51+
private static final int NODE_STRUCT_NEXT_OFFSET = 16;
52+
53+
@Substitution
54+
@TruffleBoundary
55+
public static long readSystemPropertiesInfo(@JavaType(int[].class) StaticObject offsets,
56+
@Inject EspressoLanguage language, @Inject EspressoContext context) {
57+
checkJVMCIAvailable(context.getLanguage());
58+
int[] unwrappedOffsets = offsets.unwrap(language);
59+
unwrappedOffsets[0] = NODE_STRUCT_NEXT_OFFSET;
60+
unwrappedOffsets[1] = NODE_STRUCT_KEY_OFFSET;
61+
unwrappedOffsets[2] = NODE_STRUCT_VALUE_OFFSET;
62+
63+
Map<String, String> systemProperties = context.getVM().getSystemProperties();
64+
/*
65+
* The result must point at a struct with
66+
* @formatter:off
67+
* struct node {
68+
* long key; // points to UTF_8, 0x00-terminated, string
69+
* long value; // null or points to UTF_8, 0x00-terminated, string
70+
* long next; // null or points to another node
71+
* }
72+
* @formatter:on
73+
*/
74+
// Convert the strings and find the allocation size
75+
long size = 0;
76+
byte[][] keys = new byte[systemProperties.size()][];
77+
byte[][] values = new byte[systemProperties.size()][];
78+
int i = 0;
79+
for (Map.Entry<String, String> entry : systemProperties.entrySet()) {
80+
String key = entry.getKey();
81+
String value = entry.getValue();
82+
83+
size += NODE_STRUCT_SIZE;
84+
keys[i] = key.getBytes(StandardCharsets.UTF_8);
85+
size += keys[i].length + 1;
86+
if (value != null) {
87+
values[i] = value.getBytes(StandardCharsets.UTF_8);
88+
size += values[i].length + 1;
89+
}
90+
i++;
91+
}
92+
93+
// Allocate the buffer
94+
TruffleObject allocated = context.getNativeAccess().allocateMemory(size);
95+
long ptr = NativeUtils.interopAsPointer(allocated);
96+
ByteBuffer buffer = NativeUtils.directByteBuffer(ptr, size);
97+
for (i = 0; i < keys.length; i++) {
98+
/* Layout:
99+
* @formatter:off
100+
* this block:
101+
* long key; -> key
102+
* long value; 0 or -> value
103+
* long next; 0 or -> next block
104+
* utf8 key;
105+
* utf8 value; (if != null)
106+
* next block:
107+
* ...
108+
* @formatter:on
109+
*/
110+
long nodePtr = ptr + buffer.position();
111+
long keyPtr = nodePtr + NODE_STRUCT_SIZE;
112+
long keyLen = keys[i].length + 1;
113+
long valuePtr;
114+
long valueLen;
115+
if (values[i] == null) {
116+
valuePtr = 0;
117+
valueLen = 0;
118+
} else {
119+
valuePtr = keyPtr + keyLen;
120+
valueLen = values[i].length + 1;
121+
}
122+
long nextPtr;
123+
if (i + 1 < keys.length) {
124+
nextPtr = nodePtr + NODE_STRUCT_SIZE + keyLen + valueLen;
125+
assert nextPtr == keyPtr + keyLen + valueLen;
126+
} else {
127+
nextPtr = 0;
128+
}
129+
buffer.putLong(keyPtr);
130+
buffer.putLong(valuePtr);
131+
buffer.putLong(nextPtr);
132+
buffer.put(keys[i]);
133+
buffer.put((byte) 0);
134+
if (values[i] != null) {
135+
buffer.put(values[i]);
136+
buffer.put((byte) 0);
137+
}
138+
}
139+
assert buffer.position() == size;
140+
141+
/*
142+
* Note: the buffer is leaked, this is OK since there is usually only one context per
143+
* process using JVMCI. If there are more contexts needed, we should remember the pointer
144+
* and cleanup on context finalization.
145+
*/
146+
return ptr;
147+
}
148+
}

espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/VM.java

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
import java.time.Instant;
5353
import java.util.ArrayList;
5454
import java.util.Arrays;
55+
import java.util.Collections;
5556
import java.util.HashMap;
5657
import java.util.List;
5758
import java.util.Map;
@@ -215,6 +216,9 @@ public final class VM extends NativeEnv {
215216
};
216217
private volatile @Pointer TruffleObject zipLibrary;
217218

219+
// The initial system properties
220+
private Map<String, String> systemProperties;
221+
218222
public void attachThread(Thread hostThread) {
219223
if (hostThread != Thread.currentThread()) {
220224
getLogger().warning("unimplemented: attachThread for non-current thread: " + hostThread);
@@ -2502,6 +2506,13 @@ public int setNumberedProperty(String property, List<String> values, String prov
25022506
}
25032507
}
25042508

2509+
public synchronized Map<String, String> getSystemProperties() {
2510+
if (systemProperties == null) {
2511+
systemProperties = Collections.unmodifiableMap(buildPropertiesMap().map);
2512+
}
2513+
return systemProperties;
2514+
}
2515+
25052516
private PropertiesMap buildPropertiesMap() {
25062517
PropertiesMap map = new PropertiesMap();
25072518
OptionValues options = getContext().getEnv().getOptions();
@@ -2587,7 +2598,7 @@ private PropertiesMap buildPropertiesMap() {
25872598
@VmImpl(isJni = true)
25882599
@TruffleBoundary
25892600
public @JavaType(Properties.class) StaticObject JVM_InitProperties(@JavaType(Properties.class) StaticObject properties) {
2590-
Map<String, String> props = buildPropertiesMap().map;
2601+
Map<String, String> props = getSystemProperties();
25912602
Method setProperty = properties.getKlass().lookupMethod(Names.setProperty, Signatures.Object_String_String);
25922603
for (Map.Entry<String, String> entry : props.entrySet()) {
25932604
setProperty.invokeWithConversions(properties, entry.getKey(), entry.getValue());
@@ -2598,7 +2609,7 @@ private PropertiesMap buildPropertiesMap() {
25982609
@VmImpl(isJni = true)
25992610
@TruffleBoundary
26002611
public @JavaType(String[].class) StaticObject JVM_GetProperties(@Inject EspressoLanguage language) {
2601-
Map<String, String> props = buildPropertiesMap().map;
2612+
Map<String, String> props = getSystemProperties();
26022613
StaticObject array = getMeta().java_lang_String.allocateReferenceArray(props.size() * 2);
26032614
int index = 0;
26042615
for (Map.Entry<String, String> entry : props.entrySet()) {

0 commit comments

Comments
 (0)