diff --git a/common.json b/common.json index e97e36e6f045..3bcf1288905d 100644 --- a/common.json +++ b/common.json @@ -4,7 +4,7 @@ "Jsonnet files should not include this file directly but use ci/common.jsonnet instead." ], - "mx_version": "7.27.5", + "mx_version": "7.27.5.1", "COMMENT.jdks": "When adding or removing JDKs keep in sync with JDKs in ci/common.jsonnet", "jdks": { @@ -45,13 +45,13 @@ "labsjdk-ee-21-llvm": {"name": "labsjdk", "version": "ee-21.0.2+13-jvmci-23.1-b33-sulong", "platformspecific": true }, "graalvm-ee-21": {"name": "graalvm-java21", "version": "23.1.3", "platformspecific": true }, - "oraclejdk-latest": {"name": "jpg-jdk", "version": "23", "build_id": "jdk-23+37", "platformspecific": true, "extrabundles": ["static-libs"]}, - "labsjdk-ce-latest": {"name": "labsjdk", "version": "ce-23+37-jvmci-b01", "platformspecific": true }, - "labsjdk-ce-latestDebug": {"name": "labsjdk", "version": "ce-23+37-jvmci-b01-debug", "platformspecific": true }, - "labsjdk-ce-latest-llvm": {"name": "labsjdk", "version": "ce-23+37-jvmci-b01-sulong", "platformspecific": true }, - "labsjdk-ee-latest": {"name": "labsjdk", "version": "ee-23+37-jvmci-b01", "platformspecific": true }, - "labsjdk-ee-latestDebug": {"name": "labsjdk", "version": "ee-23+37-jvmci-b01-debug", "platformspecific": true }, - "labsjdk-ee-latest-llvm": {"name": "labsjdk", "version": "ee-23+37-jvmci-b01-sulong", "platformspecific": true } + "oraclejdk-latest": {"name": "jpg-jdk", "version": "23", "build_id": "jdk-23.0.1+11", "platformspecific": true, "extrabundles": ["static-libs"]}, + "labsjdk-ce-latest": {"name": "labsjdk", "version": "ce-23.0.1+11-jvmci-b01", "platformspecific": true }, + "labsjdk-ce-latestDebug": {"name": "labsjdk", "version": "ce-23.0.1+11-jvmci-b01-debug", "platformspecific": true }, + "labsjdk-ce-latest-llvm": {"name": "labsjdk", "version": "ce-23.0.1+11-jvmci-b01-sulong", "platformspecific": true }, + "labsjdk-ee-latest": {"name": "labsjdk", "version": "ee-23.0.1+11-jvmci-b01", "platformspecific": true }, + "labsjdk-ee-latestDebug": {"name": "labsjdk", "version": "ee-23.0.1+11-jvmci-b01-debug", "platformspecific": true }, + "labsjdk-ee-latest-llvm": {"name": "labsjdk", "version": "ee-23.0.1+11-jvmci-b01-sulong", "platformspecific": true } }, "eclipse": { diff --git a/compiler/mx.compiler/suite.py b/compiler/mx.compiler/suite.py index acaf9ca09f38..fdd9471ed689 100644 --- a/compiler/mx.compiler/suite.py +++ b/compiler/mx.compiler/suite.py @@ -4,7 +4,7 @@ "sourceinprojectwhitelist" : [], "groupId" : "org.graalvm.compiler", - "version" : "24.1.0.1", + "version" : "24.1.1.0", "release" : False, "url" : "http://www.graalvm.org/", "developer" : { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/JVMCIVersionCheck.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/JVMCIVersionCheck.java index c0108551f746..6781458475a9 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/JVMCIVersionCheck.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/JVMCIVersionCheck.java @@ -55,8 +55,8 @@ public final class JVMCIVersionCheck { private static final Map> JVMCI_MIN_VERSIONS = Map.of( "21", Map.of(DEFAULT_VENDOR_ENTRY, createLegacyVersion(23, 1, 33)), "23", Map.of( - "Oracle Corporation", createLabsJDKVersion("23+37", 1), - DEFAULT_VENDOR_ENTRY, createLabsJDKVersion("23+37", 1))); + "Oracle Corporation", createLabsJDKVersion("23.0.1+11", 1), + DEFAULT_VENDOR_ENTRY, createLabsJDKVersion("23.0.1+11", 1))); private static final int NA = 0; /** * Minimum Java release supported by Graal. diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java index ea22cb9a22c8..6972b3efaa2e 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java @@ -212,7 +212,7 @@ public static Plugins create(HotSpotGraalRuntimeProvider graalRuntime, OptionValues options, TargetDescription target, BarrierSet barrierSet) { - InvocationPlugins invocationPlugins = new HotSpotInvocationPlugins(graalRuntime, config, compilerConfiguration, options); + InvocationPlugins invocationPlugins = new HotSpotInvocationPlugins(graalRuntime, config, compilerConfiguration, options, target); Plugins plugins = new Plugins(invocationPlugins); plugins.appendNodePlugin(new HotSpotExceptionDispatchPlugin(config, wordTypes.getWordKind())); diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotInvocationPlugins.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotInvocationPlugins.java index 697fb9464461..015a271d8ca7 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotInvocationPlugins.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotInvocationPlugins.java @@ -24,8 +24,8 @@ */ package jdk.graal.compiler.hotspot.meta; -import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime; import static jdk.graal.compiler.hotspot.HotSpotGraalServices.isIntrinsicAvailable; +import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime; import java.lang.reflect.Type; import java.util.ArrayList; @@ -37,6 +37,7 @@ import org.graalvm.collections.EconomicSet; import org.graalvm.collections.MapCursor; import org.graalvm.collections.Pair; + import jdk.graal.compiler.debug.GraalError; import jdk.graal.compiler.debug.TTY; import jdk.graal.compiler.graph.Node; @@ -49,7 +50,7 @@ import jdk.graal.compiler.options.OptionValues; import jdk.graal.compiler.phases.tiers.CompilerConfiguration; import jdk.graal.compiler.replacements.nodes.MacroInvokable; - +import jdk.vm.ci.code.TargetDescription; import jdk.vm.ci.hotspot.VMIntrinsicMethod; import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.ResolvedJavaType; @@ -73,11 +74,11 @@ record MethodKey(String name, String descriptor) { private final EconomicMap> disabledIntrinsics = EconomicMap.create(); - HotSpotInvocationPlugins(HotSpotGraalRuntimeProvider graalRuntime, GraalHotSpotVMConfig config, CompilerConfiguration compilerConfiguration, OptionValues options) { + HotSpotInvocationPlugins(HotSpotGraalRuntimeProvider graalRuntime, GraalHotSpotVMConfig config, CompilerConfiguration compilerConfiguration, OptionValues options, TargetDescription target) { this.graalRuntime = graalRuntime; this.config = config; if (Options.WarnMissingIntrinsic.getValue(options)) { - this.unimplementedIntrinsics = new UnimplementedGraalIntrinsics(graalRuntime.getTarget().arch); + this.unimplementedIntrinsics = new UnimplementedGraalIntrinsics(target.arch); } else { this.unimplementedIntrinsics = null; } diff --git a/espresso/mx.espresso/suite.py b/espresso/mx.espresso/suite.py index 1125bdcf08e0..a9d1f03619eb 100644 --- a/espresso/mx.espresso/suite.py +++ b/espresso/mx.espresso/suite.py @@ -24,7 +24,7 @@ suite = { "mxversion": "7.27.1", "name": "espresso", - "version" : "24.1.0.1", + "version" : "24.1.1.0", "release" : False, "groupId" : "org.graalvm.espresso", "url" : "https://www.graalvm.org/reference-manual/java-on-truffle/", diff --git a/regex/mx.regex/suite.py b/regex/mx.regex/suite.py index 421321ac38ea..1e03cdd10d72 100644 --- a/regex/mx.regex/suite.py +++ b/regex/mx.regex/suite.py @@ -43,7 +43,7 @@ "name" : "regex", - "version" : "24.1.0.1", + "version" : "24.1.1.0", "release" : False, "groupId" : "org.graalvm.regex", "url" : "http://www.graalvm.org/", diff --git a/sdk/mx.sdk/suite.py b/sdk/mx.sdk/suite.py index e9f9985279dc..ffa1e49ffe7b 100644 --- a/sdk/mx.sdk/suite.py +++ b/sdk/mx.sdk/suite.py @@ -41,7 +41,7 @@ suite = { "mxversion": "7.27.0", "name" : "sdk", - "version" : "24.1.0.1", + "version" : "24.1.1.0", "release" : False, "sourceinprojectwhitelist" : [], "url" : "https://github.com/oracle/graal", diff --git a/substratevm/CHANGELOG.md b/substratevm/CHANGELOG.md index 82ede13ea056..e17f235ad93a 100644 --- a/substratevm/CHANGELOG.md +++ b/substratevm/CHANGELOG.md @@ -28,6 +28,8 @@ This changelog summarizes major changes to GraalVM Native Image. * (GR-52844) Add `-Os`, a new optimization mode to configure the optimizer in a way to get the smallest code size. * (GR-49770) Add support for glob patterns in resource-config files in addition to regexp. The Tracing agent now prints entries in the glob format. * (GR-46386) Throw missing registration errors for JNI queries when the query was not included in the reachability metadata. +* (GR-54241) Streamline Native Image reachability metadata into a single `reachability-metadata.json`. The formerly-used individual metadata files (`reflection-config.json`, `resource-config.json`, etc.) are now deprecated, but will still be accepted. + Native Image will only output `reachability-metadata.json` files, and those will be readable on the previous LTS versions of GraalVM. See the [documentation](../docs/reference-manual/native-image/ReachabilityMetadata.md). ## GraalVM for JDK 22 (Internal Version 24.0.0) * (GR-48304) Red Hat added support for the JFR event ThreadAllocationStatistics. diff --git a/substratevm/mx.substratevm/mx_substratevm.py b/substratevm/mx.substratevm/mx_substratevm.py index 234393cd2d06..bf0629adbcc8 100644 --- a/substratevm/mx.substratevm/mx_substratevm.py +++ b/substratevm/mx.substratevm/mx_substratevm.py @@ -1139,7 +1139,9 @@ def _native_image_launcher_extra_jvm_args(): build_args=driver_build_args + [ '--features=com.oracle.svm.agent.NativeImageAgent$RegistrationFeature', '--enable-url-protocols=jar', - ], + ] + svm_experimental_options([ + '-H:+TreatAllTypeReachableConditionsAsTypeReached', + ]), headers=False, home_finder=False, ), @@ -1448,6 +1450,7 @@ def _native_image_configure_extra_jvm_args(): main_class='com.oracle.svm.configure.ConfigurationTool', build_args=svm_experimental_options([ '-H:-ParseRuntimeOptions', + '-H:+TreatAllTypeReachableConditionsAsTypeReached', ]), extra_jvm_args=_native_image_configure_extra_jvm_args(), home_finder=False, diff --git a/substratevm/mx.substratevm/suite.py b/substratevm/mx.substratevm/suite.py index 8b9749cb35a8..e592d797640a 100644 --- a/substratevm/mx.substratevm/suite.py +++ b/substratevm/mx.substratevm/suite.py @@ -2,7 +2,7 @@ suite = { "mxversion": "7.27.1", "name": "substratevm", - "version" : "24.1.0.1", + "version" : "24.1.1.0", "release" : False, "url" : "https://github.com/oracle/graal/tree/master/substratevm", diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ObjectScanner.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ObjectScanner.java index 372ef8e22c70..c748e34d1cb8 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ObjectScanner.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ObjectScanner.java @@ -211,6 +211,12 @@ protected void scanField(AnalysisField field, JavaConstant receiver, ScanReason } catch (UnsupportedFeatureException | AnalysisError.TypeNotFoundError ex) { unsupportedFeatureDuringFieldScan(bb, field, receiver, ex, reason); + } catch (AnalysisError analysisError) { + if (analysisError.getCause() instanceof UnsupportedFeatureException ex) { + unsupportedFeatureDuringFieldScan(bb, field, receiver, ex, reason); + } else { + throw analysisError; + } } } diff --git a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ConfigurationConditionPrintable.java b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ConfigurationConditionPrintable.java index d9a4eda47730..0344046c7736 100644 --- a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ConfigurationConditionPrintable.java +++ b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ConfigurationConditionPrintable.java @@ -35,10 +35,14 @@ import jdk.graal.compiler.util.json.JsonWriter; final class ConfigurationConditionPrintable { - static void printConditionAttribute(UnresolvedConfigurationCondition condition, JsonWriter writer) throws IOException { + static void printConditionAttribute(UnresolvedConfigurationCondition condition, JsonWriter writer, boolean combinedFile) throws IOException { if (!condition.isAlwaysTrue()) { writer.quote(CONDITIONAL_KEY).appendFieldSeparator().appendObjectStart(); - writer.quote(condition.isRuntimeChecked() ? TYPE_REACHED_KEY : TYPE_REACHABLE_KEY).appendFieldSeparator().quote(condition.getTypeName()); + /* + * typeReachable conditions are emitted as typeReached in reachability-metadata.json. + * typeReached conditions are emitted as typeReachable in resource-config.json + */ + writer.quote(combinedFile ? TYPE_REACHED_KEY : TYPE_REACHABLE_KEY).appendFieldSeparator().quote(condition.getTypeName()); writer.appendObjectEnd().appendSeparator(); } } diff --git a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ConfigurationType.java b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ConfigurationType.java index 7284a8120bf9..39d0bcf00ca1 100644 --- a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ConfigurationType.java +++ b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ConfigurationType.java @@ -460,7 +460,7 @@ public synchronized void setAllPublicConstructors(ConfigurationMemberAccessibili @Override public synchronized void printJson(JsonWriter writer) throws IOException { writer.appendObjectStart(); - ConfigurationConditionPrintable.printConditionAttribute(condition, writer); + ConfigurationConditionPrintable.printConditionAttribute(condition, writer, true); writer.quote("type").appendFieldSeparator(); typeDescriptor.printJson(writer); diff --git a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ParserConfigurationAdapter.java b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ParserConfigurationAdapter.java index c653e9206892..39657123cec2 100644 --- a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ParserConfigurationAdapter.java +++ b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ParserConfigurationAdapter.java @@ -103,73 +103,73 @@ public void registerConstructor(UnresolvedConfigurationCondition condition, bool @Override public void registerPublicClasses(UnresolvedConfigurationCondition condition, ConfigurationType type) { - VMError.guarantee(condition.equals(type.getCondition()), "condition is already a part of the type"); + VMError.guarantee(condition.isAlwaysTrue() || condition.equals(type.getCondition()), "condition is already a part of the type"); type.setAllPublicClasses(); } @Override public void registerDeclaredClasses(UnresolvedConfigurationCondition condition, ConfigurationType type) { - VMError.guarantee(condition.equals(type.getCondition()), "condition is already a part of the type"); + VMError.guarantee(condition.isAlwaysTrue() || condition.equals(type.getCondition()), "condition is already a part of the type"); type.setAllDeclaredClasses(); } @Override public void registerRecordComponents(UnresolvedConfigurationCondition condition, ConfigurationType type) { - VMError.guarantee(condition.equals(type.getCondition()), "condition is already a part of the type"); + VMError.guarantee(condition.isAlwaysTrue() || condition.equals(type.getCondition()), "condition is already a part of the type"); type.setAllRecordComponents(); } @Override public void registerPermittedSubclasses(UnresolvedConfigurationCondition condition, ConfigurationType type) { - VMError.guarantee(condition.equals(type.getCondition()), "condition is already a part of the type"); + VMError.guarantee(condition.isAlwaysTrue() || condition.equals(type.getCondition()), "condition is already a part of the type"); type.setAllPermittedSubclasses(); } @Override public void registerNestMembers(UnresolvedConfigurationCondition condition, ConfigurationType type) { - VMError.guarantee(condition.equals(type.getCondition()), "condition is already a part of the type"); + VMError.guarantee(condition.isAlwaysTrue() || condition.equals(type.getCondition()), "condition is already a part of the type"); type.setAllNestMembers(); } @Override public void registerSigners(UnresolvedConfigurationCondition condition, ConfigurationType type) { - VMError.guarantee(condition.equals(type.getCondition()), "condition is already a part of the type"); + VMError.guarantee(condition.isAlwaysTrue() || condition.equals(type.getCondition()), "condition is already a part of the type"); type.setAllSigners(); } @Override public void registerPublicFields(UnresolvedConfigurationCondition condition, boolean queriedOnly, ConfigurationType type) { - VMError.guarantee(condition.equals(type.getCondition()), "condition is already a part of the type"); + VMError.guarantee(condition.isAlwaysTrue() || condition.equals(type.getCondition()), "condition is already a part of the type"); type.setAllPublicFields(queriedOnly ? ConfigurationMemberAccessibility.QUERIED : ConfigurationMemberAccessibility.ACCESSED); } @Override public void registerDeclaredFields(UnresolvedConfigurationCondition condition, boolean queriedOnly, ConfigurationType type) { - VMError.guarantee(condition.equals(type.getCondition()), "condition is already a part of the type"); + VMError.guarantee(condition.isAlwaysTrue() || condition.equals(type.getCondition()), "condition is already a part of the type"); type.setAllDeclaredFields(queriedOnly ? ConfigurationMemberAccessibility.QUERIED : ConfigurationMemberAccessibility.ACCESSED); } @Override public void registerPublicMethods(UnresolvedConfigurationCondition condition, boolean queriedOnly, ConfigurationType type) { - VMError.guarantee(condition.equals(type.getCondition()), "condition is already a part of the type"); + VMError.guarantee(condition.isAlwaysTrue() || condition.equals(type.getCondition()), "condition is already a part of the type"); type.setAllPublicMethods(queriedOnly ? ConfigurationMemberAccessibility.QUERIED : ConfigurationMemberAccessibility.ACCESSED); } @Override public void registerDeclaredMethods(UnresolvedConfigurationCondition condition, boolean queriedOnly, ConfigurationType type) { - VMError.guarantee(condition.equals(type.getCondition()), "condition is already a part of the type"); + VMError.guarantee(condition.isAlwaysTrue() || condition.equals(type.getCondition()), "condition is already a part of the type"); type.setAllDeclaredMethods(queriedOnly ? ConfigurationMemberAccessibility.QUERIED : ConfigurationMemberAccessibility.ACCESSED); } @Override public void registerPublicConstructors(UnresolvedConfigurationCondition condition, boolean queriedOnly, ConfigurationType type) { - VMError.guarantee(condition.equals(type.getCondition()), "condition is already a part of the type"); + VMError.guarantee(condition.isAlwaysTrue() || condition.equals(type.getCondition()), "condition is already a part of the type"); type.setAllPublicConstructors(queriedOnly ? ConfigurationMemberAccessibility.QUERIED : ConfigurationMemberAccessibility.ACCESSED); } @Override public void registerDeclaredConstructors(UnresolvedConfigurationCondition condition, boolean queriedOnly, ConfigurationType type) { - VMError.guarantee(condition.equals(type.getCondition()), "condition is already a part of the type"); + VMError.guarantee(condition.isAlwaysTrue() || condition.equals(type.getCondition()), "condition is already a part of the type"); type.setAllDeclaredConstructors(queriedOnly ? ConfigurationMemberAccessibility.QUERIED : ConfigurationMemberAccessibility.ACCESSED); } diff --git a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ProxyConfiguration.java b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ProxyConfiguration.java index 73fc92121bd2..64296045273d 100644 --- a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ProxyConfiguration.java +++ b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ProxyConfiguration.java @@ -110,25 +110,30 @@ public void printJson(JsonWriter writer) throws IOException { public static void printProxyInterfaces(JsonWriter writer, List>> lists) throws IOException { lists.sort(ConditionalElement.comparator(ProxyConfiguration::compareList)); - writer.append('['); - writer.indent(); - String prefix = ""; + writer.appendArrayStart(); + boolean firstProxy = true; for (ConditionalElement> list : lists) { - writer.append(prefix).newline(); - writer.append('{').indent().newline(); - ConfigurationConditionPrintable.printConditionAttribute(list.condition(), writer); - writer.quote("interfaces").append(":").append('['); - String typePrefix = ""; + if (firstProxy) { + firstProxy = false; + } else { + writer.appendSeparator(); + } + writer.appendObjectStart(); + ConfigurationConditionPrintable.printConditionAttribute(list.condition(), writer, false); + writer.quote("interfaces").appendFieldSeparator().appendArrayStart(); + boolean firstType = true; for (String type : list.element()) { - writer.append(typePrefix).quote(type); - typePrefix = ","; + if (firstType) { + firstType = false; + } else { + writer.appendSeparator(); + } + writer.quote(type); } - writer.append(']').unindent().newline(); - writer.append('}'); - prefix = ","; + writer.appendArrayEnd(); + writer.appendObjectEnd(); } - writer.unindent().newline(); - writer.append(']'); + writer.appendArrayEnd(); } @Override diff --git a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ResourceConfiguration.java b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ResourceConfiguration.java index 50b7ac8199f1..a5b7b8f766e9 100644 --- a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ResourceConfiguration.java +++ b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ResourceConfiguration.java @@ -336,19 +336,19 @@ public boolean anyBundleMatches(UnresolvedConfigurationCondition condition, Stri @Override public void printJson(JsonWriter writer) throws IOException { printGlobsJson(writer, true); - writer.appendSeparator().newline(); - printBundlesJson(writer); + writer.appendSeparator(); + printBundlesJson(writer, true); } @Override public void printLegacyJson(JsonWriter writer) throws IOException { - writer.appendObjectStart().indent().newline(); + writer.appendObjectStart(); printResourcesJson(writer); - writer.appendSeparator().newline(); - printBundlesJson(writer); - writer.appendSeparator().newline(); + writer.appendSeparator(); + printBundlesJson(writer, false); + writer.appendSeparator(); printGlobsJson(writer, false); - writer.unindent().newline().appendObjectEnd(); + writer.appendObjectEnd(); } void printResourcesJson(JsonWriter writer) throws IOException { @@ -363,14 +363,14 @@ void printResourcesJson(JsonWriter writer) throws IOException { writer.appendObjectEnd(); } - void printBundlesJson(JsonWriter writer) throws IOException { + void printBundlesJson(JsonWriter writer, boolean combinedFile) throws IOException { writer.quote(BUNDLES_KEY).appendFieldSeparator(); - JsonPrinter.printCollection(writer, bundles.keySet(), ConditionalElement.comparator(), (p, w) -> printResourceBundle(bundles.get(p), w)); + JsonPrinter.printCollection(writer, bundles.keySet(), ConditionalElement.comparator(), (p, w) -> printResourceBundle(bundles.get(p), w, combinedFile)); } - void printGlobsJson(JsonWriter writer, boolean useResourcesFieldName) throws IOException { - writer.quote(useResourcesFieldName ? RESOURCES_KEY : GLOBS_KEY).appendFieldSeparator(); - JsonPrinter.printCollection(writer, addedGlobs, ConditionalElement.comparator(ResourceEntry.comparator()), ResourceConfiguration::conditionalGlobElementJson); + void printGlobsJson(JsonWriter writer, boolean combinedFile) throws IOException { + writer.quote(combinedFile ? RESOURCES_KEY : GLOBS_KEY).appendFieldSeparator(); + JsonPrinter.printCollection(writer, addedGlobs, ConditionalElement.comparator(ResourceEntry.comparator()), (p, w) -> conditionalGlobElementJson(p, w, combinedFile)); } @Override @@ -378,9 +378,9 @@ public ConfigurationParser createParser(boolean strictMetadata) { return ResourceConfigurationParser.create(strictMetadata, ConfigurationConditionResolver.identityResolver(), new ResourceConfiguration.ParserAdapter(this), true); } - private static void printResourceBundle(BundleConfiguration config, JsonWriter writer) throws IOException { + private static void printResourceBundle(BundleConfiguration config, JsonWriter writer, boolean combinedFile) throws IOException { writer.appendObjectStart(); - ConfigurationConditionPrintable.printConditionAttribute(config.condition, writer); + ConfigurationConditionPrintable.printConditionAttribute(config.condition, writer, combinedFile); writer.quote("name").appendFieldSeparator().quote(config.baseName); if (!config.locales.isEmpty()) { writer.appendSeparator().quote("locales").appendFieldSeparator(); @@ -411,11 +411,11 @@ public boolean supportsCombinedFile() { return true; } - private static void conditionalGlobElementJson(ConditionalElement p, JsonWriter w) throws IOException { + private static void conditionalGlobElementJson(ConditionalElement p, JsonWriter w, boolean combinedFile) throws IOException { String pattern = p.element().pattern(); String module = p.element().module(); w.appendObjectStart(); - ConfigurationConditionPrintable.printConditionAttribute(p.condition(), w); + ConfigurationConditionPrintable.printConditionAttribute(p.condition(), w, combinedFile); if (module != null) { w.quote("module").appendFieldSeparator().quote(module).appendSeparator(); } @@ -425,7 +425,7 @@ private static void conditionalGlobElementJson(ConditionalElement private static void conditionalRegexElementJson(ConditionalElement p, JsonWriter w) throws IOException { w.appendObjectStart(); - ConfigurationConditionPrintable.printConditionAttribute(p.condition(), w); + ConfigurationConditionPrintable.printConditionAttribute(p.condition(), w, false); w.quote("pattern").appendFieldSeparator().quote(p.element()); w.appendObjectEnd(); } diff --git a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/SerializationConfigurationLambdaCapturingType.java b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/SerializationConfigurationLambdaCapturingType.java index 0e7798618d1e..d797cdd42e58 100644 --- a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/SerializationConfigurationLambdaCapturingType.java +++ b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/SerializationConfigurationLambdaCapturingType.java @@ -57,7 +57,7 @@ public String getQualifiedJavaName() { @Override public void printJson(JsonWriter writer) throws IOException { writer.append('{').indent().newline(); - ConfigurationConditionPrintable.printConditionAttribute(condition, writer); + ConfigurationConditionPrintable.printConditionAttribute(condition, writer, false); writer.quote(SerializationConfigurationParser.NAME_KEY).append(":").quote(qualifiedJavaName); writer.unindent().newline().append('}'); diff --git a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/SerializationConfigurationType.java b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/SerializationConfigurationType.java index 21a96a62368f..bc6bc8fcadb0 100644 --- a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/SerializationConfigurationType.java +++ b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/SerializationConfigurationType.java @@ -35,6 +35,9 @@ import jdk.graal.compiler.util.json.JsonPrintable; import jdk.graal.compiler.util.json.JsonWriter; +import static com.oracle.svm.core.configure.ConfigurationParser.NAME_KEY; +import static com.oracle.svm.core.configure.ConfigurationParser.TYPE_KEY; + public class SerializationConfigurationType implements JsonPrintable, Comparable { private final UnresolvedConfigurationCondition condition; private final String qualifiedJavaName; @@ -66,17 +69,17 @@ public UnresolvedConfigurationCondition getCondition() { @Override public void printJson(JsonWriter writer) throws IOException { - printJson(writer, SerializationConfigurationParser.TYPE_KEY); + printJson(writer, true); } public void printLegacyJson(JsonWriter writer) throws IOException { - printJson(writer, SerializationConfigurationParser.NAME_KEY); + printJson(writer, false); } - private void printJson(JsonWriter writer, String key) throws IOException { + private void printJson(JsonWriter writer, boolean combinedFile) throws IOException { writer.appendObjectStart(); - ConfigurationConditionPrintable.printConditionAttribute(condition, writer); - writer.quote(key).appendFieldSeparator().quote(qualifiedJavaName); + ConfigurationConditionPrintable.printConditionAttribute(condition, writer, combinedFile); + writer.quote(combinedFile ? TYPE_KEY : NAME_KEY).appendFieldSeparator().quote(qualifiedJavaName); if (qualifiedCustomTargetConstructorJavaName != null) { writer.appendSeparator(); writer.quote(SerializationConfigurationParser.CUSTOM_TARGET_CONSTRUCTOR_CLASS_KEY).appendFieldSeparator() 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 49cd77da70d3..33fc4adeaf59 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 @@ -1327,8 +1327,8 @@ public void emitCode(CompilationResultBuilder crb, ResolvedJavaMethod installedC // A branch estimation was wrong, now retry with conservative label ranges, this // should always work resetForEmittingCode(crb); - crb.setConservativeLabelRanges(); crb.resetForEmittingCode(); + crb.setConservativeLabelRanges(); crb.emitLIR(); finalizeCode(crb); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/LegacyResourceConfigurationParser.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/LegacyResourceConfigurationParser.java index 0f680cb44899..ed068c6690c9 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/LegacyResourceConfigurationParser.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/LegacyResourceConfigurationParser.java @@ -25,9 +25,16 @@ package com.oracle.svm.core.configure; import java.net.URI; +import java.util.Collections; +import java.util.List; +import java.util.function.BiConsumer; import org.graalvm.collections.EconomicMap; import org.graalvm.collections.MapCursor; +import org.graalvm.nativeimage.impl.UnresolvedConfigurationCondition; + +import com.oracle.svm.core.TypeResult; +import com.oracle.svm.core.jdk.resources.CompressedGlobTrie.CompressedGlobTrie; final class LegacyResourceConfigurationParser extends ResourceConfigurationParser { LegacyResourceConfigurationParser(ConfigurationConditionResolver conditionResolver, ResourcesRegistry registry, boolean strictConfiguration) { @@ -64,4 +71,61 @@ private void parseTopLevelObject(EconomicMap obj) { parseGlobsObject(globsObject); } } + + @Override + protected UnresolvedConfigurationCondition parseCondition(EconomicMap condition) { + return parseCondition(condition, false); + } + + @SuppressWarnings("unchecked") + private void parseResourcesObject(Object resourcesObject) { + if (resourcesObject instanceof EconomicMap) { // New format + EconomicMap resourcesObjectMap = (EconomicMap) resourcesObject; + checkAttributes(resourcesObjectMap, "resource descriptor object", Collections.singleton("includes"), Collections.singleton("excludes")); + Object includesObject = resourcesObjectMap.get("includes"); + Object excludesObject = resourcesObjectMap.get("excludes"); + + List includes = asList(includesObject, "Attribute 'includes' must be a list of resources"); + for (Object object : includes) { + parsePatternEntry(object, (condition, pattern) -> registry.addResources(condition, pattern), + (condition, module, glob) -> registry.addGlob(condition, module, glob), "'includes' list"); + } + + if (excludesObject != null) { + List excludes = asList(excludesObject, "Attribute 'excludes' must be a list of resources"); + for (Object object : excludes) { + parsePatternEntry(object, registry::ignoreResources, null, "'excludes' list"); + } + } + } else { // Old format: may be deprecated in future versions + List resources = asList(resourcesObject, "Attribute 'resources' must be a list of resources"); + for (Object object : resources) { + parsePatternEntry(object, (condition, pattern) -> registry.addResources(condition, pattern), + (condition, module, glob) -> registry.addGlob(condition, module, glob), "'resources' list"); + } + } + } + + private void parsePatternEntry(Object data, BiConsumer resourceRegistry, GlobPatternConsumer globRegistry, String parentType) { + EconomicMap resource = asMap(data, "Elements of " + parentType + " must be a resource descriptor object"); + checkAttributes(resource, "regex resource descriptor object", Collections.singletonList("pattern"), Collections.singletonList(CONDITIONAL_KEY)); + TypeResult resolvedConfigurationCondition = conditionResolver.resolveCondition(parseCondition(resource, false)); + if (!resolvedConfigurationCondition.isPresent()) { + return; + } + + Object valueObject = resource.get("pattern"); + String value = asString(valueObject, "pattern"); + + /* Parse fully literal regex as globs */ + if (value.startsWith("\\Q") && value.endsWith("\\E") && value.indexOf("\\E") == value.lastIndexOf("\\E")) { + String globValue = value.substring("\\Q".length(), value.length() - "\\E".length()); + if (CompressedGlobTrie.validatePattern(globValue).isEmpty()) { + globRegistry.accept(resolvedConfigurationCondition.get(), null, globValue); + return; + } + } + + resourceRegistry.accept(resolvedConfigurationCondition.get(), value); + } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ResourceConfigurationParser.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ResourceConfigurationParser.java index f1927c8c0c9e..a44353ca437a 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ResourceConfigurationParser.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ResourceConfigurationParser.java @@ -28,10 +28,10 @@ import java.util.Collections; import java.util.List; import java.util.Locale; -import java.util.function.BiConsumer; import java.util.stream.Collectors; import org.graalvm.collections.EconomicMap; +import org.graalvm.nativeimage.impl.UnresolvedConfigurationCondition; import com.oracle.svm.core.TypeResult; import com.oracle.svm.core.jdk.localization.LocalizationSupport; @@ -64,38 +64,13 @@ protected void parseBundlesObject(Object bundlesObject) { } } - @SuppressWarnings("unchecked") - protected void parseResourcesObject(Object resourcesObject) { - if (resourcesObject instanceof EconomicMap) { // New format - EconomicMap resourcesObjectMap = (EconomicMap) resourcesObject; - checkAttributes(resourcesObjectMap, "resource descriptor object", Collections.singleton("includes"), Collections.singleton("excludes")); - Object includesObject = resourcesObjectMap.get("includes"); - Object excludesObject = resourcesObjectMap.get("excludes"); - - List includes = asList(includesObject, "Attribute 'includes' must be a list of resources"); - for (Object object : includes) { - parsePatternEntry(object, registry::addResources, "'includes' list"); - } - - if (excludesObject != null) { - List excludes = asList(excludesObject, "Attribute 'excludes' must be a list of resources"); - for (Object object : excludes) { - parsePatternEntry(object, registry::ignoreResources, "'excludes' list"); - } - } - } else { // Old format: may be deprecated in future versions - List resources = asList(resourcesObject, "Attribute 'resources' must be a list of resources"); - for (Object object : resources) { - parsePatternEntry(object, registry::addResources, "'resources' list"); - } - } - } + protected abstract UnresolvedConfigurationCondition parseCondition(EconomicMap condition); private void parseBundle(Object bundle) { EconomicMap resource = asMap(bundle, "Elements of 'bundles' list must be a bundle descriptor object"); checkAttributes(resource, "bundle descriptor object", Collections.singletonList("name"), Arrays.asList("locales", "classNames", "condition")); String basename = asString(resource.get("name")); - TypeResult resolvedConfigurationCondition = conditionResolver.resolveCondition(parseCondition(resource, false)); + TypeResult resolvedConfigurationCondition = conditionResolver.resolveCondition(parseCondition(resource)); if (!resolvedConfigurationCondition.isPresent()) { return; } @@ -133,19 +108,6 @@ private static Locale parseLocale(Object input) { return locale; } - private void parsePatternEntry(Object data, BiConsumer resourceRegistry, String parentType) { - EconomicMap resource = asMap(data, "Elements of " + parentType + " must be a resource descriptor object"); - checkAttributes(resource, "regex resource descriptor object", Collections.singletonList("pattern"), Collections.singletonList(CONDITIONAL_KEY)); - TypeResult resolvedConfigurationCondition = conditionResolver.resolveCondition(parseCondition(resource, false)); - if (!resolvedConfigurationCondition.isPresent()) { - return; - } - - Object valueObject = resource.get("pattern"); - String value = asString(valueObject, "pattern"); - resourceRegistry.accept(resolvedConfigurationCondition.get(), value); - } - protected void parseGlobsObject(Object globsObject) { List globs = asList(globsObject, "Attribute 'globs' must be a list of glob patterns"); for (Object object : globs) { @@ -153,14 +115,14 @@ protected void parseGlobsObject(Object globsObject) { } } - private interface GlobPatternConsumer { + protected interface GlobPatternConsumer { void accept(T a, String b, String c); } private void parseGlobEntry(Object data, GlobPatternConsumer resourceRegistry) { EconomicMap globObject = asMap(data, "Elements of 'globs' list must be a glob descriptor objects"); checkAttributes(globObject, "glob resource descriptor object", Collections.singletonList(GLOB_KEY), List.of(CONDITIONAL_KEY, MODULE_KEY)); - TypeResult resolvedConfigurationCondition = conditionResolver.resolveCondition(parseCondition(globObject, false)); + TypeResult resolvedConfigurationCondition = conditionResolver.resolveCondition(parseCondition(globObject)); if (!resolvedConfigurationCondition.isPresent()) { return; } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ResourceMetadataParser.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ResourceMetadataParser.java index 2e1b4720ed4a..6dcaec7c2980 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ResourceMetadataParser.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ResourceMetadataParser.java @@ -26,6 +26,9 @@ import java.net.URI; +import org.graalvm.collections.EconomicMap; +import org.graalvm.nativeimage.impl.UnresolvedConfigurationCondition; + final class ResourceMetadataParser extends ResourceConfigurationParser { ResourceMetadataParser(ConfigurationConditionResolver conditionResolver, ResourcesRegistry registry, boolean strictConfiguration) { super(conditionResolver, registry, strictConfiguration); @@ -42,4 +45,9 @@ public void parseAndRegister(Object json, URI origin) { parseBundlesObject(bundlesJson); } } + + @Override + protected UnresolvedConfigurationCondition parseCondition(EconomicMap condition) { + return parseCondition(condition, true); + } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/SecuritySubstitutions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/SecuritySubstitutions.java index 8b5eb142693c..6ace202546d0 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/SecuritySubstitutions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/SecuritySubstitutions.java @@ -199,6 +199,18 @@ final class Target_java_security_Provider { private static Target_java_security_Provider_ServiceKey previousKey; } +@TargetClass(value = java.security.Provider.class, innerClass = "Service") +final class Target_java_security_Provider_Service { + + /** + * The field is lazily initialized on first access. We already have the necessary reflection + * configuration for the reflective lookup at image run time. + */ + @Alias // + @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Reset) // + private Object constructorCache; +} + @Platforms(Platform.HOSTED_ONLY.class) class ServiceKeyComputer implements FieldValueTransformer { @Override diff --git a/substratevm/src/com.oracle.svm.driver.launcher/src/com/oracle/svm/driver/launcher/BundleLauncher.java b/substratevm/src/com.oracle.svm.driver.launcher/src/com/oracle/svm/driver/launcher/BundleLauncher.java index 70cb535cce9d..1a77c03ed26e 100644 --- a/substratevm/src/com.oracle.svm.driver.launcher/src/com/oracle/svm/driver/launcher/BundleLauncher.java +++ b/substratevm/src/com.oracle.svm.driver.launcher/src/com/oracle/svm/driver/launcher/BundleLauncher.java @@ -91,7 +91,8 @@ static String getResource(String resourceName) { } public static void main(String[] args) { - bundleFilePath = Paths.get(BundleLauncher.class.getProtectionDomain().getCodeSource().getLocation().getPath()); + String bundleLauncherPath = BundleLauncher.class.getProtectionDomain().getCodeSource().getLocation().getPath(); + bundleFilePath = Paths.get(isWindows() ? bundleLauncherPath.substring(1) : bundleLauncherPath); bundleName = bundleFilePath.getFileName().toString().replace(BUNDLE_FILE_EXTENSION, ""); agentOutputDir = bundleFilePath.getParent().resolve(Paths.get(bundleName + ".output", "launcher")); unpackBundle(); @@ -342,6 +343,10 @@ private static Path getJavaExecutable() { return getJavaHomeExecutable(binJava); } + private static boolean isWindows() { + return System.getProperty("os.name").contains("Windows"); + } + private static Path getJavaHomeExecutable(Path executable) { String javaHome = System.getenv("JAVA_HOME"); if (javaHome == null) { @@ -358,7 +363,7 @@ private static Path getJavaHomeExecutable(Path executable) { } private static Path getNativeImageExecutable() { - Path binNativeImage = Paths.get("bin", System.getProperty("os.name").contains("Windows") ? "native-image.exe" : "native-image"); + Path binNativeImage = Paths.get("bin", isWindows() ? "native-image.exe" : "native-image"); if (Files.isExecutable(buildTimeJavaHome.resolve(binNativeImage))) { return buildTimeJavaHome.resolve(binNativeImage); } diff --git a/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/BundleSupport.java b/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/BundleSupport.java index 6da7f4bb78c5..80760b01c4fa 100644 --- a/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/BundleSupport.java +++ b/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/BundleSupport.java @@ -696,9 +696,10 @@ private Path writeBundle() { nativeImage.deleteAllFiles(metaInfDir); } - Path bundleLauncherFile = Paths.get("/").resolve(BundleLauncher.class.getName().replace(".", "/") + ".class"); - try (FileSystem fs = FileSystems.newFileSystem(BundleSupport.class.getResource(bundleLauncherFile.toString()).toURI(), new HashMap<>()); - Stream walk = Files.walk(fs.getPath(bundleLauncherFile.getParent().toString()))) { + String bundleLauncherClassResource = "/" + BundleLauncher.class.getName().replace(".", "/") + ".class"; + String bundleLauncherPackageResource = "/" + BundleLauncher.class.getPackageName().replace(".", "/"); + try (FileSystem fs = FileSystems.newFileSystem(BundleSupport.class.getResource(bundleLauncherClassResource).toURI(), new HashMap<>()); + Stream walk = Files.walk(fs.getPath(bundleLauncherPackageResource))) { walk.filter(Predicate.not(Files::isDirectory)) .map(Path::toString) .forEach(sourcePath -> { @@ -714,7 +715,7 @@ private Path writeBundle() { } }); } catch (Exception e) { - throw NativeImage.showError("Failed to read bundle launcher resources '" + bundleLauncherFile.getParent() + "'", e); + throw NativeImage.showError("Failed to read bundle launcher resources '" + bundleLauncherPackageResource + "'", e); } Path pathCanonicalizationsFile = stageDir.resolve("path_canonicalizations.json"); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/methodhandles/MethodHandleFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/methodhandles/MethodHandleFeature.java index fbc2f82d0b31..e3c08b24e490 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/methodhandles/MethodHandleFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/methodhandles/MethodHandleFeature.java @@ -33,7 +33,6 @@ import java.lang.reflect.Member; import java.lang.reflect.Method; import java.util.Iterator; -import java.util.Locale; import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Supplier; @@ -163,17 +162,7 @@ public void beforeAnalysis(BeforeAnalysisAccess a) { access.registerReachabilityHandler(MethodHandleFeature::registerInvokersFunctionsForReflection, ReflectionUtil.lookupMethod(access.findClassByName("java.lang.invoke.Invokers"), "getFunction", byte.class)); - access.registerReachabilityHandler(MethodHandleFeature::registerValueConversionBoxFunctionsForReflection, - ReflectionUtil.lookupMethod(ValueConversions.class, "boxExact", Wrapper.class)); - - access.registerReachabilityHandler(MethodHandleFeature::registerValueConversionUnboxFunctionsForReflection, - ReflectionUtil.lookupMethod(ValueConversions.class, "unbox", Wrapper.class, int.class)); - - access.registerReachabilityHandler(MethodHandleFeature::registerValueConversionConvertFunctionsForReflection, - ReflectionUtil.lookupMethod(ValueConversions.class, "convertPrimitive", Wrapper.class, Wrapper.class)); - - access.registerReachabilityHandler(MethodHandleFeature::registerValueConversionIgnoreForReflection, - ReflectionUtil.lookupMethod(ValueConversions.class, "ignore")); + eagerlyInitializeValueConversionsCaches(); access.registerClassInitializerReachabilityHandler(MethodHandleFeature::registerDelegatingMHFunctionsForReflection, access.findClassByName("java.lang.invoke.DelegatingMethodHandle")); @@ -328,44 +317,32 @@ private static void registerInvokersFunctionsForReflection(DuringAnalysisAccess RuntimeReflection.register(ReflectionUtil.lookupMethod(invokersClazz, "directVarHandleTarget", access.findClassByName("java.lang.invoke.VarHandle"))); } - private static void registerValueConversionBoxFunctionsForReflection(DuringAnalysisAccess access) { - for (Wrapper type : Wrapper.values()) { - if (type.primitiveType().isPrimitive() && type != Wrapper.VOID) { - RuntimeReflection.register(ReflectionUtil.lookupMethod(ValueConversions.class, "box" + type.wrapperSimpleName(), type.primitiveType())); - } - } - } + /** + * Eagerly initialize method handle caches in {@link ValueConversions} so that 1) we avoid + * reflection registration for conversion methods, and 2) the static analysis already sees a + * consistent snapshot that does not change after analysis when the JDK needs more conversions. + */ + private static void eagerlyInitializeValueConversionsCaches() { + ValueConversions.ignore(); - private static void registerValueConversionUnboxFunctionsForReflection(DuringAnalysisAccess access) { - for (Wrapper type : Wrapper.values()) { - if (type.primitiveType().isPrimitive() && type != Wrapper.VOID) { - RuntimeReflection.register(ReflectionUtil.lookupMethod(ValueConversions.class, "unbox" + type.wrapperSimpleName(), type.wrapperType())); - RuntimeReflection.register(ReflectionUtil.lookupMethod(ValueConversions.class, "unbox" + type.wrapperSimpleName(), Object.class, boolean.class)); + for (Wrapper src : Wrapper.values()) { + if (src != Wrapper.VOID && src.primitiveType().isPrimitive()) { + ValueConversions.boxExact(src); + + ValueConversions.unboxExact(src, false); + ValueConversions.unboxExact(src, true); + ValueConversions.unboxWiden(src); + ValueConversions.unboxCast(src); } - } - } - private static void registerValueConversionConvertFunctionsForReflection(DuringAnalysisAccess access) { - for (Wrapper src : Wrapper.values()) { - for (Wrapper dest : Wrapper.values()) { - if (src != dest && src.primitiveType().isPrimitive() && src != Wrapper.VOID && dest.primitiveType().isPrimitive() && dest != Wrapper.VOID) { - RuntimeReflection.register(ReflectionUtil.lookupMethod(ValueConversions.class, valueConverterName(src, dest), src.primitiveType())); + for (Wrapper dst : Wrapper.values()) { + if (src != Wrapper.VOID && dst != Wrapper.VOID && (src == dst || (src.primitiveType().isPrimitive() && dst.primitiveType().isPrimitive()))) { + ValueConversions.convertPrimitive(src, dst); } } } } - private static String valueConverterName(Wrapper src, Wrapper dest) { - String srcType = src.primitiveSimpleName(); - String destType = dest.primitiveSimpleName(); - /* Capitalize first letter of destination type */ - return srcType + "To" + destType.substring(0, 1).toUpperCase(Locale.ROOT) + destType.substring(1); - } - - private static void registerValueConversionIgnoreForReflection(DuringAnalysisAccess access) { - RuntimeReflection.register(ReflectionUtil.lookupMethod(ValueConversions.class, "ignore", Object.class)); - } - private static void registerDelegatingMHFunctionsForReflection(DuringAnalysisAccess access) { Class delegatingMHClazz = access.findClassByName("java.lang.invoke.DelegatingMethodHandle"); RuntimeReflection.register(ReflectionUtil.lookupMethod(delegatingMHClazz, "getTarget")); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionDataBuilder.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionDataBuilder.java index f72a66457480..edca92946a65 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionDataBuilder.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionDataBuilder.java @@ -86,7 +86,6 @@ import com.oracle.svm.core.hub.ClassForNameSupport; import com.oracle.svm.core.hub.DynamicHub; import com.oracle.svm.core.reflect.SubstrateAccessor; -import com.oracle.svm.core.util.UserError; import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.ConditionalConfigurationRegistry; import com.oracle.svm.hosted.FeatureImpl.BeforeAnalysisAccessImpl; @@ -178,7 +177,7 @@ public void beforeAnalysis(BeforeAnalysisAccessImpl beforeAnalysisAccess) { private void runConditionalInAnalysisTask(ConfigurationCondition condition, Consumer task) { if (sealed) { - throw UserError.abort("Too late to add classes, methods, and fields for reflective access. Registration must happen in a Feature before the analysis has finished."); + throw new UnsupportedFeatureException("Too late to add classes, methods, and fields for reflective access. Registration must happen in a Feature before the analysis has finished."); } if (universe != null) { @@ -1167,11 +1166,15 @@ public RecordComponent[] getRecordComponents(Class type) { @Override public void registerHeapDynamicHub(Object object, ScanReason reason) { - assert !sealed; DynamicHub hub = (DynamicHub) object; Class javaClass = hub.getHostedJavaClass(); - if (heapDynamicHubs.add(hub) && !SubstitutionReflectivityFilter.shouldExclude(javaClass, metaAccess, universe)) { - registerTypesForClass(metaAccess.lookupJavaType(javaClass), javaClass); + if (heapDynamicHubs.add(hub)) { + if (sealed) { + throw new UnsupportedFeatureException("Registering new class for reflection when the image heap is already sealed: " + javaClass); + } + if (!SubstitutionReflectivityFilter.shouldExclude(javaClass, metaAccess, universe)) { + registerTypesForClass(metaAccess.lookupJavaType(javaClass), javaClass); + } } } @@ -1183,24 +1186,32 @@ public Set getHeapDynamicHubs() { @Override public void registerHeapReflectionField(Field reflectField, ScanReason reason) { - assert !sealed; AnalysisField analysisField = metaAccess.lookupJavaField(reflectField); - if (heapFields.put(analysisField, reflectField) == null && !SubstitutionReflectivityFilter.shouldExclude(reflectField, metaAccess, universe)) { - registerTypesForField(analysisField, reflectField, false); - if (analysisField.getDeclaringClass().isAnnotation()) { - processAnnotationField(ConfigurationCondition.alwaysTrue(), reflectField); + if (heapFields.put(analysisField, reflectField) == null) { + if (sealed) { + throw new UnsupportedFeatureException("Registering new field for reflection when the image heap is already sealed: " + reflectField); + } + if (!SubstitutionReflectivityFilter.shouldExclude(reflectField, metaAccess, universe)) { + registerTypesForField(analysisField, reflectField, false); + if (analysisField.getDeclaringClass().isAnnotation()) { + processAnnotationField(ConfigurationCondition.alwaysTrue(), reflectField); + } } } } @Override public void registerHeapReflectionExecutable(Executable reflectExecutable, ScanReason reason) { - assert !sealed; AnalysisMethod analysisMethod = metaAccess.lookupJavaMethod(reflectExecutable); - if (heapMethods.put(analysisMethod, reflectExecutable) == null && !SubstitutionReflectivityFilter.shouldExclude(reflectExecutable, metaAccess, universe)) { - registerTypesForMethod(analysisMethod, reflectExecutable); - if (reflectExecutable instanceof Method && reflectExecutable.getDeclaringClass().isAnnotation()) { - processAnnotationMethod(false, (Method) reflectExecutable); + if (heapMethods.put(analysisMethod, reflectExecutable) == null) { + if (sealed) { + throw new UnsupportedFeatureException("Registering new method for reflection when the image heap is already sealed: " + reflectExecutable); + } + if (!SubstitutionReflectivityFilter.shouldExclude(reflectExecutable, metaAccess, universe)) { + registerTypesForMethod(analysisMethod, reflectExecutable); + if (reflectExecutable instanceof Method && reflectExecutable.getDeclaringClass().isAnnotation()) { + processAnnotationMethod(false, (Method) reflectExecutable); + } } } } diff --git a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleJFRFeature.java b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleJFRFeature.java index 1607b8176bc9..9bdb2dabb8eb 100644 --- a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleJFRFeature.java +++ b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleJFRFeature.java @@ -66,6 +66,6 @@ public List> getRequiredFeatures() { } private static boolean isEnabled() { - return ImageSingletons.contains(TruffleFeature.class) && ImageSingletons.contains(JfrFeature.class); + return ImageSingletons.contains(TruffleFeature.class) && JfrFeature.isInConfiguration(true); } } diff --git a/tools/mx.tools/suite.py b/tools/mx.tools/suite.py index 765637b02fed..2898f67c04e8 100644 --- a/tools/mx.tools/suite.py +++ b/tools/mx.tools/suite.py @@ -26,7 +26,7 @@ "defaultLicense" : "GPLv2-CPE", "groupId" : "org.graalvm.tools", - "version" : "24.1.0.1", + "version" : "24.1.1.0", "release" : False, "url" : "http://openjdk.java.net/projects/graal", "developer" : { diff --git a/truffle/external_repos/simplelanguage/pom.xml b/truffle/external_repos/simplelanguage/pom.xml index 65259103ef24..e8202504732c 100644 --- a/truffle/external_repos/simplelanguage/pom.xml +++ b/truffle/external_repos/simplelanguage/pom.xml @@ -47,7 +47,7 @@ UTF-8 jdt_apt - 24.1.0-dev + 24.1.1-dev 17 17 org.graalvm.sl.launcher/com.oracle.truffle.sl.launcher.SLMain diff --git a/truffle/external_repos/simpletool/pom.xml b/truffle/external_repos/simpletool/pom.xml index 26385c8cf881..f9d964e782d6 100644 --- a/truffle/external_repos/simpletool/pom.xml +++ b/truffle/external_repos/simpletool/pom.xml @@ -48,7 +48,7 @@ ${graalvm.version} simpletool - 24.1.0-dev + 24.1.1-dev UTF-8 17 17 diff --git a/truffle/mx.truffle/suite.py b/truffle/mx.truffle/suite.py index 2fda531cf1e1..a52f5fa4eadf 100644 --- a/truffle/mx.truffle/suite.py +++ b/truffle/mx.truffle/suite.py @@ -41,7 +41,7 @@ suite = { "mxversion": "7.27.1", "name" : "truffle", - "version" : "24.1.0.1", + "version" : "24.1.1.0", "release" : False, "groupId" : "org.graalvm.truffle", "sourceinprojectwhitelist" : [], diff --git a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/debug/TraceCompilationListener.java b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/debug/TraceCompilationListener.java index 0a8bdbb61261..13d65e9f510b 100644 --- a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/debug/TraceCompilationListener.java +++ b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/debug/TraceCompilationListener.java @@ -85,7 +85,7 @@ public static void install(OptimizedTruffleRuntime runtime) { private static final String QUEUED_FORMAT = "opt queued " + TARGET_FORMAT + "|" + TIER_FORMAT + "|" + COUNT_THRESHOLD_FORMAT + "|" + QUEUE_FORMAT + "|UTC %s|Src %s"; private static final String UNQUEUED_FORMAT = "opt unque. " + TARGET_FORMAT + "|" + TIER_FORMAT + "|" + COUNT_THRESHOLD_FORMAT + "|" + QUEUE_FORMAT + "|UTC %s|Src %s|Reason %s"; private static final String START_FORMAT = "opt start " + TARGET_FORMAT + "|" + TIER_FORMAT + "|Priority %9d|Rate %.6f|" + QUEUE_FORMAT + "|UTC %s|Src %s"; - private static final String DONE_FORMAT = "opt done " + TARGET_FORMAT + "|" + TIER_FORMAT + "|Time %18s|AST %4d|Inlined %3dY %3dN|IR %6d/%6d|CodeSize %7d|Addr %7s|UTC %s|Src %s"; + private static final String DONE_FORMAT = "opt done " + TARGET_FORMAT + "|" + TIER_FORMAT + "|Time %18s|AST %4d|Inlined %3dY %3dN|IR %6d/%6d|CodeSize %7d|Addr 0x%012x|UTC %s|Src %s"; private static final String FAILED_FORMAT = "opt failed " + TARGET_FORMAT + "|" + TIER_FORMAT + "|Time %18s|Reason: %s|UTC %s|Src %s"; private static final String INV_FORMAT = "opt inval. " + TARGET_FORMAT + " |UTC %s|Src %s|Reason %s"; private static final String DEOPT_FORMAT = "opt deopt " + TARGET_FORMAT + "| |UTC %s|Src %s"; @@ -244,7 +244,7 @@ public void onCompilationSuccess(OptimizedCallTarget target, AbstractCompilation compilation.nodeCountPartialEval, graph == null ? 0 : graph.getNodeCount(), result == null ? 0 : result.getTargetCodeSize(), - "0x" + Long.toHexString(target.getCodeAddress()), + target.getCodeAddress(), TIME_FORMATTER.format(ZonedDateTime.now()), formatSourceSection(safeSourceSection(target)))); currentCompilation.remove(); diff --git a/vm/mx.vm/suite.py b/vm/mx.vm/suite.py index 78b095f57b9f..108e91197558 100644 --- a/vm/mx.vm/suite.py +++ b/vm/mx.vm/suite.py @@ -1,6 +1,6 @@ suite = { "name": "vm", - "version" : "24.1.0.1", + "version" : "24.1.1.0", "mxversion": "7.27.0", "release" : False, "groupId" : "org.graalvm", @@ -33,7 +33,7 @@ "name": "graal-nodejs", "subdir": True, "dynamic": True, - "version": "5ed929b213fff8a888ebfeeb86cbfd5b3b74f663", + "version": "2e808370bb8c82ecef81700afd890864f75ef9a1", "urls" : [ {"url" : "https://github.com/graalvm/graaljs.git", "kind" : "git"}, ] @@ -42,7 +42,7 @@ "name": "graal-js", "subdir": True, "dynamic": True, - "version": "5ed929b213fff8a888ebfeeb86cbfd5b3b74f663", + "version": "2e808370bb8c82ecef81700afd890864f75ef9a1", "urls": [ {"url": "https://github.com/graalvm/graaljs.git", "kind" : "git"}, ] @@ -65,7 +65,7 @@ }, { "name": "graalpython", - "version": "c0c790b029c1e6fa58c6f4345f749fa5d5453bf2", + "version": "a5d4b186761583a006ed3cfc6f0887c6306bc696", "dynamic": True, "urls": [ {"url": "https://github.com/graalvm/graalpython.git", "kind": "git"}, diff --git a/wasm/mx.wasm/suite.py b/wasm/mx.wasm/suite.py index ec16262c5097..7e8d09bae42b 100644 --- a/wasm/mx.wasm/suite.py +++ b/wasm/mx.wasm/suite.py @@ -42,7 +42,7 @@ "mxversion": "7.27.1", "name" : "wasm", "groupId" : "org.graalvm.wasm", - "version" : "24.1.0.1", + "version" : "24.1.1.0", "versionConflictResolution" : "latest", "url" : "http://graalvm.org/", "developer" : { diff --git a/wasm/src/org.graalvm.wasm.benchmark/src/org/graalvm/wasm/benchmark/WasmBenchmarkSuiteBase.java b/wasm/src/org.graalvm.wasm.benchmark/src/org/graalvm/wasm/benchmark/WasmBenchmarkSuiteBase.java index 0a078cfb97cd..6caf376a8b9a 100644 --- a/wasm/src/org.graalvm.wasm.benchmark/src/org/graalvm/wasm/benchmark/WasmBenchmarkSuiteBase.java +++ b/wasm/src/org.graalvm.wasm.benchmark/src/org/graalvm/wasm/benchmark/WasmBenchmarkSuiteBase.java @@ -48,8 +48,8 @@ import java.util.Objects; import org.graalvm.polyglot.Context; +import org.graalvm.polyglot.PolyglotAccess; import org.graalvm.polyglot.Value; -import org.graalvm.wasm.WasmContextOptions; import org.graalvm.wasm.WasmLanguage; import org.graalvm.wasm.utils.WasmBinaryTools; import org.graalvm.wasm.utils.cases.WasmCase; @@ -71,6 +71,7 @@ public abstract static class WasmBenchmarkState { private Value benchmarkTeardownEach; private Value benchmarkRun; private Value result; + private int benchmarkTeardownEachArgs = 1; /** * Benchmarks must not be validated via their standard out, unlike tests. @@ -97,6 +98,8 @@ public void setup() throws IOException, InterruptedException { } } }); + // Export "WebAssembly" binding. + contextBuilder.allowPolyglotAccess(PolyglotAccess.ALL); context = contextBuilder.build(); var sources = benchmarkCase.getSources(EnumSet.noneOf(WasmBinaryTools.WabtOption.class)); @@ -112,6 +115,18 @@ public void setup() throws IOException, InterruptedException { throw new RuntimeException(String.format("No benchmarkRun method in %s.", benchmarkCase.name())); } + // Workaround for photon benchmark's nullary benchmarkTeardownEach(). + Value api = context.getPolyglotBindings().getMember("WebAssembly"); + if (api != null) { + Value funcType = api.getMember("func_type"); + if (funcType != null) { + Value signature = funcType.execute(benchmarkTeardownEach); + if (signature.asString().contains("()")) { + benchmarkTeardownEachArgs = 0; + } + } + } + if (benchmarkSetupOnce != null) { benchmarkSetupOnce.execute(); } @@ -141,12 +156,20 @@ public void setupInvocation() { // is that they can handle VM-state side-effects. // We may support benchmark-specific teardown actions in the future (at the invocation // level). - benchmarkSetupEach.execute(); + if (benchmarkSetupEach != null) { + benchmarkSetupEach.execute(); + } } @TearDown(Level.Invocation) public void teardownInvocation() { - benchmarkTeardownEach.execute(0); + if (benchmarkTeardownEach != null) { + if (benchmarkTeardownEachArgs == 0) { + benchmarkTeardownEach.execute(); + } else { + benchmarkTeardownEach.execute(0); + } + } } public void run() { diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/BinaryParser.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/BinaryParser.java index 4b3cfdf1146a..8cad2f83c2dd 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/BinaryParser.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/BinaryParser.java @@ -1033,7 +1033,7 @@ private CodeEntry readFunction(int functionIndex, byte[] locals, byte[] resultTy // Do not override the code entry offset when rereading the function. module.setCodeEntryOffset(codeEntryIndex, bytecodeEndOffset); } - return new CodeEntry(functionIndex, state.maxStackSize(), locals, resultTypes, callNodes, bytecodeStartOffset, bytecodeEndOffset); + return new CodeEntry(functionIndex, state.maxStackSize(), locals, resultTypes, callNodes, bytecodeStartOffset, bytecodeEndOffset, state.usesMemoryZero()); } private void readNumericInstructions(ParserState state, int opcode) { diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/SymbolTable.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/SymbolTable.java index 296b9f7d0efa..a9258baaed9a 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/SymbolTable.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/SymbolTable.java @@ -179,12 +179,12 @@ public TableInfo(int initialSize, int maximumSize, byte elemType) { public static class MemoryInfo { /** - * Lower bound on memory size. + * Lower bound on memory size (in pages of 64 kiB). */ public final long initialSize; /** - * Upper bound on memory size. + * Upper bound on memory size (in pages of 64 kiB). *

* Note: this is the upper bound defined by the module. A memory instance might * have a lower internal max allowed size in practice. diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmCodeEntry.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmCodeEntry.java index c50d10d03275..3c9dcf85854c 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmCodeEntry.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmCodeEntry.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -52,14 +52,16 @@ public final class WasmCodeEntry { private final BranchProfile errorBranch = BranchProfile.create(); private final int numLocals; private final int resultCount; + private final boolean usesMemoryZero; - public WasmCodeEntry(WasmFunction function, byte[] bytecode, byte[] localTypes, byte[] resultTypes) { + public WasmCodeEntry(WasmFunction function, byte[] bytecode, byte[] localTypes, byte[] resultTypes, boolean usesMemoryZero) { this.function = function; this.bytecode = bytecode; this.localTypes = localTypes; this.numLocals = localTypes.length; this.resultTypes = resultTypes; this.resultCount = resultTypes.length; + this.usesMemoryZero = usesMemoryZero; } public WasmFunction function() { @@ -94,6 +96,10 @@ public void errorBranch() { errorBranch.enter(); } + public boolean usesMemoryZero() { + return usesMemoryZero; + } + @Override public String toString() { return "wasm-code-entry:" + functionIndex(); diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmInstantiator.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmInstantiator.java index 505c50e8f2c5..ad1b3ae9a35e 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmInstantiator.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmInstantiator.java @@ -495,7 +495,7 @@ private CallTarget instantiateCodeEntry(WasmContext context, WasmModule module, assert context.language().isMultiContext(); return cachedTarget; } - final WasmCodeEntry wasmCodeEntry = new WasmCodeEntry(function, module.bytecode(), codeEntry.localTypes(), codeEntry.resultTypes()); + final WasmCodeEntry wasmCodeEntry = new WasmCodeEntry(function, module.bytecode(), codeEntry.localTypes(), codeEntry.resultTypes(), codeEntry.usesMemoryZero()); final FrameDescriptor frameDescriptor = createFrameDescriptor(codeEntry.localTypes(), codeEntry.maxStackSize()); final WasmInstrumentableFunctionNode functionNode = instantiateFunctionNode(module, instance, wasmCodeEntry, codeEntry); final WasmRootNode rootNode; diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/WebAssembly.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/WebAssembly.java index 3bd50851883e..8ea8fd84fe20 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/WebAssembly.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/WebAssembly.java @@ -297,8 +297,15 @@ private static void checkArgumentCount(Object[] args, int requiredCount) { private static byte[] toBytes(Object source) { InteropLibrary interop = InteropLibrary.getUncached(source); - if (interop.hasArrayElements(source)) { - try { + try { + if (interop.hasBufferElements(source)) { + long size = interop.getBufferSize(source); + if (size == (int) size) { + byte[] bytes = new byte[(int) size]; + interop.readBuffer(source, 0, bytes, 0, (int) size); + return bytes; + } + } else if (interop.hasArrayElements(source)) { long size = interop.getArraySize(source); if (size == (int) size) { byte[] bytes = new byte[(int) size]; @@ -312,9 +319,9 @@ private static byte[] toBytes(Object source) { } return bytes; } - } catch (InteropException iex) { - throw cannotConvertToBytesError(iex); } + } catch (InteropException iex) { + throw cannotConvertToBytesError(iex); } throw cannotConvertToBytesError(null); } diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/ByteArrayWasmMemory.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/ByteArrayWasmMemory.java index 7a80645035df..950b3278bb4d 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/ByteArrayWasmMemory.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/ByteArrayWasmMemory.java @@ -51,38 +51,39 @@ import java.nio.ByteBuffer; import java.util.Arrays; -import com.oracle.truffle.api.CompilerDirectives; import org.graalvm.wasm.api.Vector128; import org.graalvm.wasm.exception.Failure; import org.graalvm.wasm.exception.WasmException; -import com.oracle.truffle.api.Assumption; -import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; +import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.memory.ByteArraySupport; import com.oracle.truffle.api.nodes.Node; final class ByteArrayWasmMemory extends WasmMemory { - private final WasmByteArrayBuffer byteArrayBuffer; + private byte[] dynamicBuffer; private ByteArrayWasmMemory(long declaredMinSize, long declaredMaxSize, long initialSize, long maxAllowedSize, boolean indexType64, boolean shared) { super(declaredMinSize, declaredMaxSize, initialSize, maxAllowedSize, indexType64, shared); - this.byteArrayBuffer = new WasmByteArrayBuffer(); - this.byteArrayBuffer.allocate(initialSize * MEMORY_PAGE_SIZE); + this.dynamicBuffer = allocateStatic(initialSize * MEMORY_PAGE_SIZE); } ByteArrayWasmMemory(long declaredMinSize, long declaredMaxSize, long maxAllowedSize, boolean indexType64, boolean shared) { this(declaredMinSize, declaredMaxSize, declaredMinSize, maxAllowedSize, indexType64, shared); } + private byte[] buffer() { + return dynamicBuffer; + } + @Override public long size() { - return byteArrayBuffer.size(); + return byteSize() / MEMORY_PAGE_SIZE; } @Override public long byteSize() { - return byteArrayBuffer.byteSize(); + return buffer().length; } @Override @@ -96,7 +97,9 @@ public synchronized long grow(long extraPageSize) { // Condition above and limit on maxPageSize (see ModuleLimits#MAX_MEMORY_SIZE) // ensure computation of targetByteSize does not overflow. final long targetByteSize = multiplyExact(addExact(size(), extraPageSize), MEMORY_PAGE_SIZE); - byteArrayBuffer.grow(targetByteSize); + final byte[] currentBuffer = buffer(); + allocate(targetByteSize); + System.arraycopy(currentBuffer, 0, buffer(), 0, currentBuffer.length); currentMinSize = size() + extraPageSize; invokeGrowCallback(); return previousSize; @@ -106,15 +109,16 @@ public synchronized long grow(long extraPageSize) { } @Override + @TruffleBoundary public void reset() { - byteArrayBuffer.reset(declaredMinSize * MEMORY_PAGE_SIZE); + allocate(declaredMinSize * MEMORY_PAGE_SIZE); currentMinSize = declaredMinSize; } @Override public int load_i32(Node node, long address) { try { - return ByteArraySupport.littleEndian().getInt(byteArrayBuffer.buffer(), address); + return ByteArraySupport.littleEndian().getInt(buffer(), address); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 4); } @@ -123,7 +127,7 @@ public int load_i32(Node node, long address) { @Override public long load_i64(Node node, long address) { try { - return ByteArraySupport.littleEndian().getLong(byteArrayBuffer.buffer(), address); + return ByteArraySupport.littleEndian().getLong(buffer(), address); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 8); } @@ -132,7 +136,7 @@ public long load_i64(Node node, long address) { @Override public float load_f32(Node node, long address) { try { - return ByteArraySupport.littleEndian().getFloat(byteArrayBuffer.buffer(), address); + return ByteArraySupport.littleEndian().getFloat(buffer(), address); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 4); } @@ -141,7 +145,7 @@ public float load_f32(Node node, long address) { @Override public double load_f64(Node node, long address) { try { - return ByteArraySupport.littleEndian().getDouble(byteArrayBuffer.buffer(), address); + return ByteArraySupport.littleEndian().getDouble(buffer(), address); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 8); } @@ -150,7 +154,7 @@ public double load_f64(Node node, long address) { @Override public int load_i32_8s(Node node, long address) { try { - return ByteArraySupport.littleEndian().getByte(byteArrayBuffer.buffer(), address); + return ByteArraySupport.littleEndian().getByte(buffer(), address); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 1); } @@ -159,7 +163,7 @@ public int load_i32_8s(Node node, long address) { @Override public int load_i32_8u(Node node, long address) { try { - return 0x0000_00ff & ByteArraySupport.littleEndian().getByte(byteArrayBuffer.buffer(), address); + return 0x0000_00ff & ByteArraySupport.littleEndian().getByte(buffer(), address); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 1); } @@ -168,7 +172,7 @@ public int load_i32_8u(Node node, long address) { @Override public int load_i32_16s(Node node, long address) { try { - return ByteArraySupport.littleEndian().getShort(byteArrayBuffer.buffer(), address); + return ByteArraySupport.littleEndian().getShort(buffer(), address); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 2); } @@ -177,7 +181,7 @@ public int load_i32_16s(Node node, long address) { @Override public int load_i32_16u(Node node, long address) { try { - return 0x0000_ffff & ByteArraySupport.littleEndian().getShort(byteArrayBuffer.buffer(), address); + return 0x0000_ffff & ByteArraySupport.littleEndian().getShort(buffer(), address); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 2); } @@ -186,7 +190,7 @@ public int load_i32_16u(Node node, long address) { @Override public long load_i64_8s(Node node, long address) { try { - return ByteArraySupport.littleEndian().getByte(byteArrayBuffer.buffer(), address); + return ByteArraySupport.littleEndian().getByte(buffer(), address); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 1); } @@ -195,7 +199,7 @@ public long load_i64_8s(Node node, long address) { @Override public long load_i64_8u(Node node, long address) { try { - return 0x0000_0000_0000_00ffL & ByteArraySupport.littleEndian().getByte(byteArrayBuffer.buffer(), address); + return 0x0000_0000_0000_00ffL & ByteArraySupport.littleEndian().getByte(buffer(), address); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 1); } @@ -204,7 +208,7 @@ public long load_i64_8u(Node node, long address) { @Override public long load_i64_16s(Node node, long address) { try { - return ByteArraySupport.littleEndian().getShort(byteArrayBuffer.buffer(), address); + return ByteArraySupport.littleEndian().getShort(buffer(), address); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 2); } @@ -213,7 +217,7 @@ public long load_i64_16s(Node node, long address) { @Override public long load_i64_16u(Node node, long address) { try { - return 0x0000_0000_0000_ffffL & ByteArraySupport.littleEndian().getShort(byteArrayBuffer.buffer(), address); + return 0x0000_0000_0000_ffffL & ByteArraySupport.littleEndian().getShort(buffer(), address); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 2); } @@ -222,7 +226,7 @@ public long load_i64_16u(Node node, long address) { @Override public long load_i64_32s(Node node, long address) { try { - return ByteArraySupport.littleEndian().getInt(byteArrayBuffer.buffer(), address); + return ByteArraySupport.littleEndian().getInt(buffer(), address); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 4); } @@ -231,7 +235,7 @@ public long load_i64_32s(Node node, long address) { @Override public long load_i64_32u(Node node, long address) { try { - return 0x0000_0000_ffff_ffffL & ByteArraySupport.littleEndian().getInt(byteArrayBuffer.buffer(), address); + return 0x0000_0000_ffff_ffffL & ByteArraySupport.littleEndian().getInt(buffer(), address); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 4); } @@ -239,8 +243,8 @@ public long load_i64_32u(Node node, long address) { @Override public Vector128 load_i128(Node node, long address) { - if (ByteArraySupport.littleEndian().inBounds(byteArrayBuffer.buffer(), address, Vector128.BYTES)) { - return new Vector128(Arrays.copyOfRange(byteArrayBuffer.buffer(), (int) address, (int) address + Vector128.BYTES)); + if (ByteArraySupport.littleEndian().inBounds(buffer(), address, Vector128.BYTES)) { + return new Vector128(Arrays.copyOfRange(buffer(), (int) address, (int) address + Vector128.BYTES)); } else { throw trapOutOfBounds(node, address, 16); } @@ -249,7 +253,7 @@ public Vector128 load_i128(Node node, long address) { @Override public void store_i32(Node node, long address, int value) { try { - ByteArraySupport.littleEndian().putInt(byteArrayBuffer.buffer(), address, value); + ByteArraySupport.littleEndian().putInt(buffer(), address, value); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 4); } @@ -258,7 +262,7 @@ public void store_i32(Node node, long address, int value) { @Override public void store_i64(Node node, long address, long value) { try { - ByteArraySupport.littleEndian().putLong(byteArrayBuffer.buffer(), address, value); + ByteArraySupport.littleEndian().putLong(buffer(), address, value); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 8); } @@ -268,7 +272,7 @@ public void store_i64(Node node, long address, long value) { @Override public void store_f32(Node node, long address, float value) { try { - ByteArraySupport.littleEndian().putFloat(byteArrayBuffer.buffer(), address, value); + ByteArraySupport.littleEndian().putFloat(buffer(), address, value); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 4); } @@ -277,7 +281,7 @@ public void store_f32(Node node, long address, float value) { @Override public void store_f64(Node node, long address, double value) { try { - ByteArraySupport.littleEndian().putDouble(byteArrayBuffer.buffer(), address, value); + ByteArraySupport.littleEndian().putDouble(buffer(), address, value); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 8); } @@ -286,7 +290,7 @@ public void store_f64(Node node, long address, double value) { @Override public void store_i32_8(Node node, long address, byte value) { try { - ByteArraySupport.littleEndian().putByte(byteArrayBuffer.buffer(), address, value); + ByteArraySupport.littleEndian().putByte(buffer(), address, value); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 1); } @@ -295,7 +299,7 @@ public void store_i32_8(Node node, long address, byte value) { @Override public void store_i32_16(Node node, long address, short value) { try { - ByteArraySupport.littleEndian().putShort(byteArrayBuffer.buffer(), address, value); + ByteArraySupport.littleEndian().putShort(buffer(), address, value); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 2); } @@ -304,7 +308,7 @@ public void store_i32_16(Node node, long address, short value) { @Override public void store_i64_8(Node node, long address, byte value) { try { - ByteArraySupport.littleEndian().putByte(byteArrayBuffer.buffer(), address, value); + ByteArraySupport.littleEndian().putByte(buffer(), address, value); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 1); } @@ -313,7 +317,7 @@ public void store_i64_8(Node node, long address, byte value) { @Override public void store_i64_16(Node node, long address, short value) { try { - ByteArraySupport.littleEndian().putShort(byteArrayBuffer.buffer(), address, value); + ByteArraySupport.littleEndian().putShort(buffer(), address, value); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 2); } @@ -322,7 +326,7 @@ public void store_i64_16(Node node, long address, short value) { @Override public void store_i64_32(Node node, long address, int value) { try { - ByteArraySupport.littleEndian().putInt(byteArrayBuffer.buffer(), address, value); + ByteArraySupport.littleEndian().putInt(buffer(), address, value); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 4); } @@ -330,8 +334,8 @@ public void store_i64_32(Node node, long address, int value) { @Override public void store_i128(Node node, long address, Vector128 value) { - if (ByteArraySupport.littleEndian().inBounds(byteArrayBuffer.buffer(), address, 16)) { - System.arraycopy(value.getBytes(), 0, byteArrayBuffer.buffer(), (int) address, 16); + if (ByteArraySupport.littleEndian().inBounds(buffer(), address, 16)) { + System.arraycopy(value.getBytes(), 0, buffer(), (int) address, 16); } else { throw trapOutOfBounds(node, address, 16); } @@ -348,7 +352,7 @@ private static void validateAtomicAddress(Node node, long address, int length) { public int atomic_load_i32(Node node, long address) { validateAtomicAddress(node, address, 4); try { - return ByteArraySupport.littleEndian().getIntVolatile(byteArrayBuffer.buffer(), address); + return ByteArraySupport.littleEndian().getIntVolatile(buffer(), address); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 4); } @@ -358,7 +362,7 @@ public int atomic_load_i32(Node node, long address) { public long atomic_load_i64(Node node, long address) { validateAtomicAddress(node, address, 8); try { - return ByteArraySupport.littleEndian().getLongVolatile(byteArrayBuffer.buffer(), address); + return ByteArraySupport.littleEndian().getLongVolatile(buffer(), address); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 8); } @@ -368,7 +372,7 @@ public long atomic_load_i64(Node node, long address) { public int atomic_load_i32_8u(Node node, long address) { validateAtomicAddress(node, address, 1); try { - return 0x0000_00ff & ByteArraySupport.littleEndian().getByteVolatile(byteArrayBuffer.buffer(), address); + return 0x0000_00ff & ByteArraySupport.littleEndian().getByteVolatile(buffer(), address); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 1); } @@ -378,7 +382,7 @@ public int atomic_load_i32_8u(Node node, long address) { public int atomic_load_i32_16u(Node node, long address) { validateAtomicAddress(node, address, 2); try { - return 0x0000_ffff & ByteArraySupport.littleEndian().getShortVolatile(byteArrayBuffer.buffer(), address); + return 0x0000_ffff & ByteArraySupport.littleEndian().getShortVolatile(buffer(), address); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 2); } @@ -388,7 +392,7 @@ public int atomic_load_i32_16u(Node node, long address) { public long atomic_load_i64_8u(Node node, long address) { validateAtomicAddress(node, address, 1); try { - return 0x0000_0000_0000_00ffL & ByteArraySupport.littleEndian().getByteVolatile(byteArrayBuffer.buffer(), address); + return 0x0000_0000_0000_00ffL & ByteArraySupport.littleEndian().getByteVolatile(buffer(), address); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 1); } @@ -398,7 +402,7 @@ public long atomic_load_i64_8u(Node node, long address) { public long atomic_load_i64_16u(Node node, long address) { validateAtomicAddress(node, address, 2); try { - return 0x0000_0000_0000_ffffL & ByteArraySupport.littleEndian().getShortVolatile(byteArrayBuffer.buffer(), address); + return 0x0000_0000_0000_ffffL & ByteArraySupport.littleEndian().getShortVolatile(buffer(), address); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 2); } @@ -408,7 +412,7 @@ public long atomic_load_i64_16u(Node node, long address) { public long atomic_load_i64_32u(Node node, long address) { validateAtomicAddress(node, address, 4); try { - return 0x0000_0000_ffff_ffffL & ByteArraySupport.littleEndian().getIntVolatile(byteArrayBuffer.buffer(), address); + return 0x0000_0000_ffff_ffffL & ByteArraySupport.littleEndian().getIntVolatile(buffer(), address); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 4); } @@ -418,7 +422,7 @@ public long atomic_load_i64_32u(Node node, long address) { public void atomic_store_i32(Node node, long address, int value) { validateAtomicAddress(node, address, 4); try { - ByteArraySupport.littleEndian().putIntVolatile(byteArrayBuffer.buffer(), address, value); + ByteArraySupport.littleEndian().putIntVolatile(buffer(), address, value); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 4); } @@ -428,7 +432,7 @@ public void atomic_store_i32(Node node, long address, int value) { public void atomic_store_i64(Node node, long address, long value) { validateAtomicAddress(node, address, 8); try { - ByteArraySupport.littleEndian().putLongVolatile(byteArrayBuffer.buffer(), address, value); + ByteArraySupport.littleEndian().putLongVolatile(buffer(), address, value); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 8); } @@ -438,7 +442,7 @@ public void atomic_store_i64(Node node, long address, long value) { public void atomic_store_i32_8(Node node, long address, byte value) { validateAtomicAddress(node, address, 1); try { - ByteArraySupport.littleEndian().putByteVolatile(byteArrayBuffer.buffer(), address, value); + ByteArraySupport.littleEndian().putByteVolatile(buffer(), address, value); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 1); } @@ -448,7 +452,7 @@ public void atomic_store_i32_8(Node node, long address, byte value) { public void atomic_store_i32_16(Node node, long address, short value) { validateAtomicAddress(node, address, 2); try { - ByteArraySupport.littleEndian().putShortVolatile(byteArrayBuffer.buffer(), address, value); + ByteArraySupport.littleEndian().putShortVolatile(buffer(), address, value); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 2); } @@ -458,7 +462,7 @@ public void atomic_store_i32_16(Node node, long address, short value) { public void atomic_store_i64_8(Node node, long address, byte value) { validateAtomicAddress(node, address, 1); try { - ByteArraySupport.littleEndian().putByteVolatile(byteArrayBuffer.buffer(), address, value); + ByteArraySupport.littleEndian().putByteVolatile(buffer(), address, value); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 1); } @@ -468,7 +472,7 @@ public void atomic_store_i64_8(Node node, long address, byte value) { public void atomic_store_i64_16(Node node, long address, short value) { validateAtomicAddress(node, address, 2); try { - ByteArraySupport.littleEndian().putShortVolatile(byteArrayBuffer.buffer(), address, value); + ByteArraySupport.littleEndian().putShortVolatile(buffer(), address, value); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 2); } @@ -478,7 +482,7 @@ public void atomic_store_i64_16(Node node, long address, short value) { public void atomic_store_i64_32(Node node, long address, int value) { validateAtomicAddress(node, address, 4); try { - ByteArraySupport.littleEndian().putIntVolatile(byteArrayBuffer.buffer(), address, value); + ByteArraySupport.littleEndian().putIntVolatile(buffer(), address, value); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 4); } @@ -488,7 +492,7 @@ public void atomic_store_i64_32(Node node, long address, int value) { public int atomic_rmw_add_i32_8u(Node node, long address, byte value) { validateAtomicAddress(node, address, 1); try { - return 0x0000_00ff & ByteArraySupport.littleEndian().getAndAddByte(byteArrayBuffer.buffer(), address, value); + return 0x0000_00ff & ByteArraySupport.littleEndian().getAndAddByte(buffer(), address, value); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 1); } @@ -498,7 +502,7 @@ public int atomic_rmw_add_i32_8u(Node node, long address, byte value) { public int atomic_rmw_add_i32_16u(Node node, long address, short value) { validateAtomicAddress(node, address, 2); try { - return 0x0000_ffff & ByteArraySupport.littleEndian().getAndAddShort(byteArrayBuffer.buffer(), address, value); + return 0x0000_ffff & ByteArraySupport.littleEndian().getAndAddShort(buffer(), address, value); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 2); } @@ -508,7 +512,7 @@ public int atomic_rmw_add_i32_16u(Node node, long address, short value) { public int atomic_rmw_add_i32(Node node, long address, int value) { validateAtomicAddress(node, address, 4); try { - return ByteArraySupport.littleEndian().getAndAddInt(byteArrayBuffer.buffer(), address, value); + return ByteArraySupport.littleEndian().getAndAddInt(buffer(), address, value); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 4); } @@ -518,7 +522,7 @@ public int atomic_rmw_add_i32(Node node, long address, int value) { public long atomic_rmw_add_i64_8u(Node node, long address, byte value) { validateAtomicAddress(node, address, 1); try { - return 0x0000_0000_0000_00ffL & ByteArraySupport.littleEndian().getAndAddByte(byteArrayBuffer.buffer(), address, value); + return 0x0000_0000_0000_00ffL & ByteArraySupport.littleEndian().getAndAddByte(buffer(), address, value); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 1); } @@ -528,7 +532,7 @@ public long atomic_rmw_add_i64_8u(Node node, long address, byte value) { public long atomic_rmw_add_i64_16u(Node node, long address, short value) { validateAtomicAddress(node, address, 2); try { - return 0x0000_0000_0000_ffffL & ByteArraySupport.littleEndian().getAndAddShort(byteArrayBuffer.buffer(), address, value); + return 0x0000_0000_0000_ffffL & ByteArraySupport.littleEndian().getAndAddShort(buffer(), address, value); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 2); } @@ -538,7 +542,7 @@ public long atomic_rmw_add_i64_16u(Node node, long address, short value) { public long atomic_rmw_add_i64_32u(Node node, long address, int value) { validateAtomicAddress(node, address, 4); try { - return 0x0000_0000_ffff_ffffL & ByteArraySupport.littleEndian().getAndAddInt(byteArrayBuffer.buffer(), address, value); + return 0x0000_0000_ffff_ffffL & ByteArraySupport.littleEndian().getAndAddInt(buffer(), address, value); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 4); } @@ -548,7 +552,7 @@ public long atomic_rmw_add_i64_32u(Node node, long address, int value) { public long atomic_rmw_add_i64(Node node, long address, long value) { validateAtomicAddress(node, address, 8); try { - return ByteArraySupport.littleEndian().getAndAddLong(byteArrayBuffer.buffer(), address, value); + return ByteArraySupport.littleEndian().getAndAddLong(buffer(), address, value); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 8); } @@ -558,7 +562,7 @@ public long atomic_rmw_add_i64(Node node, long address, long value) { public int atomic_rmw_sub_i32_8u(Node node, long address, byte value) { validateAtomicAddress(node, address, 1); try { - return 0x0000_00ff & ByteArraySupport.littleEndian().getAndAddByte(byteArrayBuffer.buffer(), address, (byte) -value); + return 0x0000_00ff & ByteArraySupport.littleEndian().getAndAddByte(buffer(), address, (byte) -value); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 1); } @@ -568,7 +572,7 @@ public int atomic_rmw_sub_i32_8u(Node node, long address, byte value) { public int atomic_rmw_sub_i32_16u(Node node, long address, short value) { validateAtomicAddress(node, address, 2); try { - return 0x0000_ffff & ByteArraySupport.littleEndian().getAndAddShort(byteArrayBuffer.buffer(), address, (short) -value); + return 0x0000_ffff & ByteArraySupport.littleEndian().getAndAddShort(buffer(), address, (short) -value); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 2); } @@ -578,7 +582,7 @@ public int atomic_rmw_sub_i32_16u(Node node, long address, short value) { public int atomic_rmw_sub_i32(Node node, long address, int value) { validateAtomicAddress(node, address, 4); try { - return ByteArraySupport.littleEndian().getAndAddInt(byteArrayBuffer.buffer(), address, -value); + return ByteArraySupport.littleEndian().getAndAddInt(buffer(), address, -value); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 4); } @@ -588,7 +592,7 @@ public int atomic_rmw_sub_i32(Node node, long address, int value) { public long atomic_rmw_sub_i64_8u(Node node, long address, byte value) { validateAtomicAddress(node, address, 1); try { - return 0x0000_0000_0000_00ffL & ByteArraySupport.littleEndian().getAndAddByte(byteArrayBuffer.buffer(), address, (byte) -value); + return 0x0000_0000_0000_00ffL & ByteArraySupport.littleEndian().getAndAddByte(buffer(), address, (byte) -value); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 1); } @@ -598,7 +602,7 @@ public long atomic_rmw_sub_i64_8u(Node node, long address, byte value) { public long atomic_rmw_sub_i64_16u(Node node, long address, short value) { validateAtomicAddress(node, address, 2); try { - return 0x0000_0000_0000_ffffL & ByteArraySupport.littleEndian().getAndAddShort(byteArrayBuffer.buffer(), address, (short) -value); + return 0x0000_0000_0000_ffffL & ByteArraySupport.littleEndian().getAndAddShort(buffer(), address, (short) -value); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 2); } @@ -608,7 +612,7 @@ public long atomic_rmw_sub_i64_16u(Node node, long address, short value) { public long atomic_rmw_sub_i64_32u(Node node, long address, int value) { validateAtomicAddress(node, address, 4); try { - return 0x0000_0000_ffff_ffffL & ByteArraySupport.littleEndian().getAndAddInt(byteArrayBuffer.buffer(), address, -value); + return 0x0000_0000_ffff_ffffL & ByteArraySupport.littleEndian().getAndAddInt(buffer(), address, -value); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 4); } @@ -618,7 +622,7 @@ public long atomic_rmw_sub_i64_32u(Node node, long address, int value) { public long atomic_rmw_sub_i64(Node node, long address, long value) { validateAtomicAddress(node, address, 8); try { - return ByteArraySupport.littleEndian().getAndAddLong(byteArrayBuffer.buffer(), address, -value); + return ByteArraySupport.littleEndian().getAndAddLong(buffer(), address, -value); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 8); } @@ -628,7 +632,7 @@ public long atomic_rmw_sub_i64(Node node, long address, long value) { public int atomic_rmw_and_i32_8u(Node node, long address, byte value) { validateAtomicAddress(node, address, 1); try { - return 0x0000_00ff & ByteArraySupport.littleEndian().getAndBitwiseAndByte(byteArrayBuffer.buffer(), address, value); + return 0x0000_00ff & ByteArraySupport.littleEndian().getAndBitwiseAndByte(buffer(), address, value); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 1); } @@ -638,7 +642,7 @@ public int atomic_rmw_and_i32_8u(Node node, long address, byte value) { public int atomic_rmw_and_i32_16u(Node node, long address, short value) { validateAtomicAddress(node, address, 2); try { - return 0x0000_ffff & ByteArraySupport.littleEndian().getAndBitwiseAndShort(byteArrayBuffer.buffer(), address, value); + return 0x0000_ffff & ByteArraySupport.littleEndian().getAndBitwiseAndShort(buffer(), address, value); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 2); } @@ -648,7 +652,7 @@ public int atomic_rmw_and_i32_16u(Node node, long address, short value) { public int atomic_rmw_and_i32(Node node, long address, int value) { validateAtomicAddress(node, address, 4); try { - return ByteArraySupport.littleEndian().getAndBitwiseAndInt(byteArrayBuffer.buffer(), address, value); + return ByteArraySupport.littleEndian().getAndBitwiseAndInt(buffer(), address, value); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 4); } @@ -658,7 +662,7 @@ public int atomic_rmw_and_i32(Node node, long address, int value) { public long atomic_rmw_and_i64_8u(Node node, long address, byte value) { validateAtomicAddress(node, address, 1); try { - return 0x0000_0000_0000_00ffL & ByteArraySupport.littleEndian().getAndBitwiseAndByte(byteArrayBuffer.buffer(), address, value); + return 0x0000_0000_0000_00ffL & ByteArraySupport.littleEndian().getAndBitwiseAndByte(buffer(), address, value); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 1); } @@ -668,7 +672,7 @@ public long atomic_rmw_and_i64_8u(Node node, long address, byte value) { public long atomic_rmw_and_i64_16u(Node node, long address, short value) { validateAtomicAddress(node, address, 2); try { - return 0x0000_0000_0000_ffffL & ByteArraySupport.littleEndian().getAndBitwiseAndShort(byteArrayBuffer.buffer(), address, value); + return 0x0000_0000_0000_ffffL & ByteArraySupport.littleEndian().getAndBitwiseAndShort(buffer(), address, value); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 2); } @@ -678,7 +682,7 @@ public long atomic_rmw_and_i64_16u(Node node, long address, short value) { public long atomic_rmw_and_i64_32u(Node node, long address, int value) { validateAtomicAddress(node, address, 4); try { - return 0x0000_0000_ffff_ffffL & ByteArraySupport.littleEndian().getAndBitwiseAndInt(byteArrayBuffer.buffer(), address, value); + return 0x0000_0000_ffff_ffffL & ByteArraySupport.littleEndian().getAndBitwiseAndInt(buffer(), address, value); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 4); } @@ -688,7 +692,7 @@ public long atomic_rmw_and_i64_32u(Node node, long address, int value) { public long atomic_rmw_and_i64(Node node, long address, long value) { validateAtomicAddress(node, address, 8); try { - return ByteArraySupport.littleEndian().getAndBitwiseAndLong(byteArrayBuffer.buffer(), address, value); + return ByteArraySupport.littleEndian().getAndBitwiseAndLong(buffer(), address, value); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 8); } @@ -698,7 +702,7 @@ public long atomic_rmw_and_i64(Node node, long address, long value) { public int atomic_rmw_or_i32_8u(Node node, long address, byte value) { validateAtomicAddress(node, address, 1); try { - return 0x0000_00ff & ByteArraySupport.littleEndian().getAndBitwiseOrByte(byteArrayBuffer.buffer(), address, value); + return 0x0000_00ff & ByteArraySupport.littleEndian().getAndBitwiseOrByte(buffer(), address, value); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 1); } @@ -708,7 +712,7 @@ public int atomic_rmw_or_i32_8u(Node node, long address, byte value) { public int atomic_rmw_or_i32_16u(Node node, long address, short value) { validateAtomicAddress(node, address, 2); try { - return 0x0000_ffff & ByteArraySupport.littleEndian().getAndBitwiseOrShort(byteArrayBuffer.buffer(), address, value); + return 0x0000_ffff & ByteArraySupport.littleEndian().getAndBitwiseOrShort(buffer(), address, value); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 2); } @@ -718,7 +722,7 @@ public int atomic_rmw_or_i32_16u(Node node, long address, short value) { public int atomic_rmw_or_i32(Node node, long address, int value) { validateAtomicAddress(node, address, 4); try { - return ByteArraySupport.littleEndian().getAndBitwiseOrInt(byteArrayBuffer.buffer(), address, value); + return ByteArraySupport.littleEndian().getAndBitwiseOrInt(buffer(), address, value); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 4); } @@ -728,7 +732,7 @@ public int atomic_rmw_or_i32(Node node, long address, int value) { public long atomic_rmw_or_i64_8u(Node node, long address, byte value) { validateAtomicAddress(node, address, 1); try { - return 0x0000_0000_0000_00ffL & ByteArraySupport.littleEndian().getAndBitwiseOrByte(byteArrayBuffer.buffer(), address, value); + return 0x0000_0000_0000_00ffL & ByteArraySupport.littleEndian().getAndBitwiseOrByte(buffer(), address, value); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 1); } @@ -738,7 +742,7 @@ public long atomic_rmw_or_i64_8u(Node node, long address, byte value) { public long atomic_rmw_or_i64_16u(Node node, long address, short value) { validateAtomicAddress(node, address, 2); try { - return 0x0000_0000_0000_ffffL & ByteArraySupport.littleEndian().getAndBitwiseOrShort(byteArrayBuffer.buffer(), address, value); + return 0x0000_0000_0000_ffffL & ByteArraySupport.littleEndian().getAndBitwiseOrShort(buffer(), address, value); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 2); } @@ -748,7 +752,7 @@ public long atomic_rmw_or_i64_16u(Node node, long address, short value) { public long atomic_rmw_or_i64_32u(Node node, long address, int value) { validateAtomicAddress(node, address, 4); try { - return 0x0000_0000_ffff_ffffL & ByteArraySupport.littleEndian().getAndBitwiseOrInt(byteArrayBuffer.buffer(), address, value); + return 0x0000_0000_ffff_ffffL & ByteArraySupport.littleEndian().getAndBitwiseOrInt(buffer(), address, value); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 4); } @@ -758,7 +762,7 @@ public long atomic_rmw_or_i64_32u(Node node, long address, int value) { public long atomic_rmw_or_i64(Node node, long address, long value) { validateAtomicAddress(node, address, 8); try { - return ByteArraySupport.littleEndian().getAndBitwiseOrLong(byteArrayBuffer.buffer(), address, value); + return ByteArraySupport.littleEndian().getAndBitwiseOrLong(buffer(), address, value); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 8); } @@ -768,7 +772,7 @@ public long atomic_rmw_or_i64(Node node, long address, long value) { public int atomic_rmw_xor_i32_8u(Node node, long address, byte value) { validateAtomicAddress(node, address, 1); try { - return 0x0000_00ff & ByteArraySupport.littleEndian().getAndBitwiseXorByte(byteArrayBuffer.buffer(), address, value); + return 0x0000_00ff & ByteArraySupport.littleEndian().getAndBitwiseXorByte(buffer(), address, value); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 1); } @@ -778,7 +782,7 @@ public int atomic_rmw_xor_i32_8u(Node node, long address, byte value) { public int atomic_rmw_xor_i32_16u(Node node, long address, short value) { validateAtomicAddress(node, address, 2); try { - return 0x0000_ffff & ByteArraySupport.littleEndian().getAndBitwiseXorShort(byteArrayBuffer.buffer(), address, value); + return 0x0000_ffff & ByteArraySupport.littleEndian().getAndBitwiseXorShort(buffer(), address, value); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 2); } @@ -788,7 +792,7 @@ public int atomic_rmw_xor_i32_16u(Node node, long address, short value) { public int atomic_rmw_xor_i32(Node node, long address, int value) { validateAtomicAddress(node, address, 4); try { - return ByteArraySupport.littleEndian().getAndBitwiseXorInt(byteArrayBuffer.buffer(), address, value); + return ByteArraySupport.littleEndian().getAndBitwiseXorInt(buffer(), address, value); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 4); } @@ -798,7 +802,7 @@ public int atomic_rmw_xor_i32(Node node, long address, int value) { public long atomic_rmw_xor_i64_8u(Node node, long address, byte value) { validateAtomicAddress(node, address, 1); try { - return 0x0000_0000_0000_00ffL & ByteArraySupport.littleEndian().getAndBitwiseXorByte(byteArrayBuffer.buffer(), address, value); + return 0x0000_0000_0000_00ffL & ByteArraySupport.littleEndian().getAndBitwiseXorByte(buffer(), address, value); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 1); } @@ -808,7 +812,7 @@ public long atomic_rmw_xor_i64_8u(Node node, long address, byte value) { public long atomic_rmw_xor_i64_16u(Node node, long address, short value) { validateAtomicAddress(node, address, 2); try { - return 0x0000_0000_0000_ffffL & ByteArraySupport.littleEndian().getAndBitwiseXorShort(byteArrayBuffer.buffer(), address, value); + return 0x0000_0000_0000_ffffL & ByteArraySupport.littleEndian().getAndBitwiseXorShort(buffer(), address, value); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 2); } @@ -818,7 +822,7 @@ public long atomic_rmw_xor_i64_16u(Node node, long address, short value) { public long atomic_rmw_xor_i64_32u(Node node, long address, int value) { validateAtomicAddress(node, address, 4); try { - return 0x0000_0000_ffff_ffffL & ByteArraySupport.littleEndian().getAndBitwiseXorInt(byteArrayBuffer.buffer(), address, value); + return 0x0000_0000_ffff_ffffL & ByteArraySupport.littleEndian().getAndBitwiseXorInt(buffer(), address, value); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 4); } @@ -828,7 +832,7 @@ public long atomic_rmw_xor_i64_32u(Node node, long address, int value) { public long atomic_rmw_xor_i64(Node node, long address, long value) { validateAtomicAddress(node, address, 8); try { - return ByteArraySupport.littleEndian().getAndBitwiseXorLong(byteArrayBuffer.buffer(), address, value); + return ByteArraySupport.littleEndian().getAndBitwiseXorLong(buffer(), address, value); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 8); } @@ -838,7 +842,7 @@ public long atomic_rmw_xor_i64(Node node, long address, long value) { public int atomic_rmw_xchg_i32_8u(Node node, long address, byte value) { validateAtomicAddress(node, address, 1); try { - return 0x0000_00ff & ByteArraySupport.littleEndian().getAndSetByte(byteArrayBuffer.buffer(), address, value); + return 0x0000_00ff & ByteArraySupport.littleEndian().getAndSetByte(buffer(), address, value); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 1); } @@ -848,7 +852,7 @@ public int atomic_rmw_xchg_i32_8u(Node node, long address, byte value) { public int atomic_rmw_xchg_i32_16u(Node node, long address, short value) { validateAtomicAddress(node, address, 2); try { - return 0x0000_ffff & ByteArraySupport.littleEndian().getAndSetShort(byteArrayBuffer.buffer(), address, value); + return 0x0000_ffff & ByteArraySupport.littleEndian().getAndSetShort(buffer(), address, value); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 2); } @@ -858,7 +862,7 @@ public int atomic_rmw_xchg_i32_16u(Node node, long address, short value) { public int atomic_rmw_xchg_i32(Node node, long address, int value) { validateAtomicAddress(node, address, 4); try { - return ByteArraySupport.littleEndian().getAndSetInt(byteArrayBuffer.buffer(), address, value); + return ByteArraySupport.littleEndian().getAndSetInt(buffer(), address, value); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 4); } @@ -868,7 +872,7 @@ public int atomic_rmw_xchg_i32(Node node, long address, int value) { public long atomic_rmw_xchg_i64_8u(Node node, long address, byte value) { validateAtomicAddress(node, address, 1); try { - return 0x0000_0000_0000_00ffL & ByteArraySupport.littleEndian().getAndSetByte(byteArrayBuffer.buffer(), address, value); + return 0x0000_0000_0000_00ffL & ByteArraySupport.littleEndian().getAndSetByte(buffer(), address, value); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 1); } @@ -878,7 +882,7 @@ public long atomic_rmw_xchg_i64_8u(Node node, long address, byte value) { public long atomic_rmw_xchg_i64_16u(Node node, long address, short value) { validateAtomicAddress(node, address, 2); try { - return 0x0000_0000_0000_ffffL & ByteArraySupport.littleEndian().getAndSetShort(byteArrayBuffer.buffer(), address, value); + return 0x0000_0000_0000_ffffL & ByteArraySupport.littleEndian().getAndSetShort(buffer(), address, value); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 2); } @@ -888,7 +892,7 @@ public long atomic_rmw_xchg_i64_16u(Node node, long address, short value) { public long atomic_rmw_xchg_i64_32u(Node node, long address, int value) { validateAtomicAddress(node, address, 4); try { - return 0x0000_0000_ffff_ffffL & ByteArraySupport.littleEndian().getAndSetInt(byteArrayBuffer.buffer(), address, value); + return 0x0000_0000_ffff_ffffL & ByteArraySupport.littleEndian().getAndSetInt(buffer(), address, value); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 4); } @@ -898,7 +902,7 @@ public long atomic_rmw_xchg_i64_32u(Node node, long address, int value) { public long atomic_rmw_xchg_i64(Node node, long address, long value) { validateAtomicAddress(node, address, 8); try { - return ByteArraySupport.littleEndian().getAndSetLong(byteArrayBuffer.buffer(), address, value); + return ByteArraySupport.littleEndian().getAndSetLong(buffer(), address, value); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 8); } @@ -908,7 +912,7 @@ public long atomic_rmw_xchg_i64(Node node, long address, long value) { public int atomic_rmw_cmpxchg_i32_8u(Node node, long address, byte expected, byte replacement) { validateAtomicAddress(node, address, 1); try { - return 0x0000_00ff & ByteArraySupport.littleEndian().compareAndExchangeByte(byteArrayBuffer.buffer(), address, expected, replacement); + return 0x0000_00ff & ByteArraySupport.littleEndian().compareAndExchangeByte(buffer(), address, expected, replacement); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 1); } @@ -918,7 +922,7 @@ public int atomic_rmw_cmpxchg_i32_8u(Node node, long address, byte expected, byt public int atomic_rmw_cmpxchg_i32_16u(Node node, long address, short expected, short replacement) { validateAtomicAddress(node, address, 2); try { - return 0x0000_ffff & ByteArraySupport.littleEndian().compareAndExchangeShort(byteArrayBuffer.buffer(), address, expected, replacement); + return 0x0000_ffff & ByteArraySupport.littleEndian().compareAndExchangeShort(buffer(), address, expected, replacement); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 2); } @@ -928,7 +932,7 @@ public int atomic_rmw_cmpxchg_i32_16u(Node node, long address, short expected, s public int atomic_rmw_cmpxchg_i32(Node node, long address, int expected, int replacement) { validateAtomicAddress(node, address, 4); try { - return ByteArraySupport.littleEndian().compareAndExchangeInt(byteArrayBuffer.buffer(), address, expected, replacement); + return ByteArraySupport.littleEndian().compareAndExchangeInt(buffer(), address, expected, replacement); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 4); } @@ -938,7 +942,7 @@ public int atomic_rmw_cmpxchg_i32(Node node, long address, int expected, int rep public long atomic_rmw_cmpxchg_i64_8u(Node node, long address, byte expected, byte replacement) { validateAtomicAddress(node, address, 1); try { - return 0x0000_0000_0000_00ffL & ByteArraySupport.littleEndian().compareAndExchangeByte(byteArrayBuffer.buffer(), address, expected, replacement); + return 0x0000_0000_0000_00ffL & ByteArraySupport.littleEndian().compareAndExchangeByte(buffer(), address, expected, replacement); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 1); } @@ -948,7 +952,7 @@ public long atomic_rmw_cmpxchg_i64_8u(Node node, long address, byte expected, by public long atomic_rmw_cmpxchg_i64_16u(Node node, long address, short expected, short replacement) { validateAtomicAddress(node, address, 2); try { - return 0x0000_0000_0000_ffffL & ByteArraySupport.littleEndian().compareAndExchangeShort(byteArrayBuffer.buffer(), address, expected, replacement); + return 0x0000_0000_0000_ffffL & ByteArraySupport.littleEndian().compareAndExchangeShort(buffer(), address, expected, replacement); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 2); } @@ -958,7 +962,7 @@ public long atomic_rmw_cmpxchg_i64_16u(Node node, long address, short expected, public long atomic_rmw_cmpxchg_i64_32u(Node node, long address, int expected, int replacement) { validateAtomicAddress(node, address, 4); try { - return 0x0000_0000_ffff_ffffL & ByteArraySupport.littleEndian().compareAndExchangeInt(byteArrayBuffer.buffer(), address, expected, replacement); + return 0x0000_0000_ffff_ffffL & ByteArraySupport.littleEndian().compareAndExchangeInt(buffer(), address, expected, replacement); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 4); } @@ -968,7 +972,7 @@ public long atomic_rmw_cmpxchg_i64_32u(Node node, long address, int expected, in public long atomic_rmw_cmpxchg_i64(Node node, long address, long expected, long replacement) { validateAtomicAddress(node, address, 8); try { - return ByteArraySupport.littleEndian().compareAndExchangeLong(byteArrayBuffer.buffer(), address, expected, replacement); + return ByteArraySupport.littleEndian().compareAndExchangeLong(buffer(), address, expected, replacement); } catch (final IndexOutOfBoundsException e) { throw trapOutOfBounds(node, address, 8); } @@ -1016,14 +1020,14 @@ public int atomic_wait64(Node node, long address, long expected, long timeout) { @Override public void initialize(byte[] source, int sourceOffset, long destinationOffset, int length) { assert destinationOffset + length <= byteSize(); - System.arraycopy(source, sourceOffset, byteArrayBuffer.buffer(), (int) destinationOffset, length); + System.arraycopy(source, sourceOffset, buffer(), (int) destinationOffset, length); } @Override @TruffleBoundary public void fill(long offset, long length, byte value) { assert offset + length <= byteSize(); - Arrays.fill(byteArrayBuffer.buffer(), (int) offset, (int) (offset + length), value); + Arrays.fill(buffer(), (int) offset, (int) (offset + length), value); } @Override @@ -1031,19 +1035,19 @@ public void copyFrom(WasmMemory source, long sourceOffset, long destinationOffse assert source instanceof ByteArrayWasmMemory; assert destinationOffset < byteSize(); ByteArrayWasmMemory s = (ByteArrayWasmMemory) source; - System.arraycopy(s.byteArrayBuffer.buffer(), (int) sourceOffset, byteArrayBuffer.buffer(), (int) destinationOffset, (int) length); + System.arraycopy(s.buffer(), (int) sourceOffset, buffer(), (int) destinationOffset, (int) length); } @Override public WasmMemory duplicate() { final ByteArrayWasmMemory other = new ByteArrayWasmMemory(declaredMinSize, declaredMaxSize, size(), maxAllowedSize, indexType64, shared); - System.arraycopy(byteArrayBuffer.buffer(), 0, other.byteArrayBuffer.buffer(), 0, (int) byteArrayBuffer.byteSize()); + System.arraycopy(buffer(), 0, other.buffer(), 0, (int) byteSize()); return other; } @Override public void close() { - byteArrayBuffer.close(); + dynamicBuffer = null; } @Override @@ -1057,7 +1061,7 @@ public int copyFromStream(Node node, InputStream stream, int offset, int length) if (outOfBounds(offset, length)) { throw trapOutOfBounds(node, offset, length); } - return stream.read(byteArrayBuffer.buffer(), offset, length); + return stream.read(buffer(), offset, length); } @Override @@ -1066,7 +1070,7 @@ public void copyToStream(Node node, OutputStream stream, int offset, int length) if (outOfBounds(offset, length)) { throw trapOutOfBounds(node, offset, length); } - stream.write(byteArrayBuffer.buffer(), offset, length); + stream.write(buffer(), offset, length); } @Override @@ -1074,74 +1078,23 @@ public void copyToBuffer(Node node, byte[] dst, long srcOffset, int dstOffset, i if (outOfBounds(srcOffset, length)) { throw trapOutOfBounds(node, srcOffset, length); } - System.arraycopy(byteArrayBuffer.buffer(), (int) srcOffset, dst, dstOffset, length); + System.arraycopy(buffer(), (int) srcOffset, dst, dstOffset, length); } - private static final class WasmByteArrayBuffer { - private static final int MAX_CONSTANT_ATTEMPTS = 5; - - @CompilationFinal private Assumption constantMemoryBufferAssumption; - - @CompilationFinal(dimensions = 0) private byte[] constantBuffer; - - private byte[] dynamicBuffer; - - private int constantAttempts = 0; - - private WasmByteArrayBuffer() { - } - - @TruffleBoundary - public void allocate(long byteSize) { - assert byteSize <= Integer.MAX_VALUE; - final int effectiveByteSize = (int) byteSize; - constantBuffer = null; - dynamicBuffer = null; - if (constantAttempts < MAX_CONSTANT_ATTEMPTS) { - constantMemoryBufferAssumption = Assumption.create("ConstantMemoryBuffer"); - constantAttempts++; - } - try { - if (constantMemoryBufferAssumption.isValid()) { - constantBuffer = new byte[effectiveByteSize]; - } else { - dynamicBuffer = new byte[effectiveByteSize]; - } - } catch (OutOfMemoryError error) { - throw WasmException.create(Failure.MEMORY_ALLOCATION_FAILED); - } - } - - byte[] buffer() { - if (constantMemoryBufferAssumption.isValid()) { - return constantBuffer; - } - return dynamicBuffer; - } - - long size() { - return buffer().length / MEMORY_PAGE_SIZE; - } - - long byteSize() { - return buffer().length; - } - - void grow(long targetSize) { - final byte[] currentBuffer = buffer(); - constantMemoryBufferAssumption.invalidate("Memory grow"); - allocate(targetSize); - System.arraycopy(currentBuffer, 0, buffer(), 0, currentBuffer.length); - } - - void reset(long byteSize) { - constantMemoryBufferAssumption.invalidate("Memory reset"); - allocate(byteSize); - } + @TruffleBoundary + private void allocate(long byteSize) { + dynamicBuffer = null; + dynamicBuffer = allocateStatic(byteSize); + } - void close() { - constantBuffer = null; - dynamicBuffer = null; + @TruffleBoundary + private static byte[] allocateStatic(long byteSize) { + assert byteSize <= Integer.MAX_VALUE : byteSize; + final int effectiveByteSize = (int) byteSize; + try { + return new byte[effectiveByteSize]; + } catch (OutOfMemoryError error) { + throw WasmException.create(Failure.MEMORY_ALLOCATION_FAILED); } } } diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/NativeWasmMemory.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/NativeWasmMemory.java index 0d2199c64a30..ee8f51e96299 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/NativeWasmMemory.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/NativeWasmMemory.java @@ -127,6 +127,7 @@ public synchronized long grow(long extraPageSize) { } @Override + @TruffleBoundary public void reset() { free(); size = declaredMinSize; @@ -953,6 +954,7 @@ public boolean freed() { return startAddress == 0; } + @TruffleBoundary private void free() { unsafe.freeMemory(startAddress); startAddress = 0; diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/UnsafeWasmMemory.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/UnsafeWasmMemory.java index 82123ccbd051..c820938fb807 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/UnsafeWasmMemory.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/UnsafeWasmMemory.java @@ -119,6 +119,7 @@ private static void validateAtomicAddress(Node node, long address, int length) { } @Override + @TruffleBoundary public void reset() { size = declaredMinSize; buffer = allocateBuffer(byteSize()); diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/WasmMemory.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/WasmMemory.java index dd8cc63464fc..d4bced208bd4 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/WasmMemory.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/WasmMemory.java @@ -838,6 +838,13 @@ protected boolean outOfBounds(long offset, long length) { return length < 0 || offset < 0 || offset > getBufferSize() - length; } + public final WasmMemory checkSize(long initialSize) { + if (byteSize() < initialSize * Sizes.MEMORY_PAGE_SIZE) { + throw CompilerDirectives.shouldNotReachHere("Memory size must not be less than initial size"); + } + return this; + } + /** * Copy data from an input stream into memory. * diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmFunctionNode.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmFunctionNode.java index af0cf6d98f0d..beccbbab99ec 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmFunctionNode.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmFunctionNode.java @@ -183,8 +183,8 @@ void updateBytecode(byte[] bytecode, int bytecodeStartOffset, int bytecodeEndOff this.notifyFunction = notifyFunction; } - private WasmMemory memory(WasmInstance instance) { - return memory(instance, 0); + private WasmMemory memory0(WasmInstance instance) { + return memory(instance, 0).checkSize(module.memoryInitialSize(0)); } private WasmMemory memory(WasmInstance instance, int index) { @@ -270,7 +270,7 @@ public Object executeBodyFromOffset(WasmContext context, WasmInstance instance, int line = startLine; // Note: The module may not have any memories. - final WasmMemory zeroMemory = module.memoryCount() == 0 ? null : memory(instance); + final WasmMemory zeroMemory = !codeEntry.usesMemoryZero() ? null : memory0(instance); check(bytecode.length, (1 << 31) - 1); @@ -4642,31 +4642,31 @@ private static boolean profileCondition(byte[] data, final int profileOffset, bo int f = rawPeekU8(data, profileOffset + 1); boolean val = condition; if (val) { + if (t == 0) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + } if (!CompilerDirectives.inInterpreter()) { - if (t == 0) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - } if (f == 0) { // Make this branch fold during PE val = true; } } else { if (t < MAX_PROFILE_VALUE) { - data[profileOffset]++; + data[profileOffset] = (byte) (t + 1); } } } else { + if (f == 0) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + } if (!CompilerDirectives.inInterpreter()) { - if (f == 0) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - } if (t == 0) { // Make this branch fold during PE val = false; } } else { if (f < MAX_PROFILE_VALUE) { - data[profileOffset + 1]++; + data[profileOffset + 1] = (byte) (f + 1); } } } diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/parser/bytecode/BytecodeParser.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/parser/bytecode/BytecodeParser.java index 22c4052c2de3..9d6df0ec3a24 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/parser/bytecode/BytecodeParser.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/parser/bytecode/BytecodeParser.java @@ -424,7 +424,8 @@ public static CodeEntry readCodeEntry(WasmModule module, byte[] bytecode, int co results = Bytecode.EMPTY_BYTES; } List callNodes = readCallNodes(bytecode, codeEntryOffset - length, codeEntryOffset); - return new CodeEntry(functionIndex, maxStackSize, locals, results, callNodes, codeEntryOffset - length, codeEntryOffset); + boolean usesMemoryZero = module.memoryCount() != 0; + return new CodeEntry(functionIndex, maxStackSize, locals, results, callNodes, codeEntryOffset - length, codeEntryOffset, usesMemoryZero); } /** diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/parser/ir/CodeEntry.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/parser/ir/CodeEntry.java index 3903e9c4328c..a3248b3c2fc7 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/parser/ir/CodeEntry.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/parser/ir/CodeEntry.java @@ -54,8 +54,9 @@ public final class CodeEntry { private final List callNodes; private final int bytecodeStartOffset; private final int bytecodeEndOffset; + private final boolean usesMemoryZero; - public CodeEntry(int functionIndex, int maxStackSize, byte[] localTypes, byte[] resultTypes, List callNodes, int startOffset, int endOffset) { + public CodeEntry(int functionIndex, int maxStackSize, byte[] localTypes, byte[] resultTypes, List callNodes, int startOffset, int endOffset, boolean usesMemoryZero) { this.functionIndex = functionIndex; this.maxStackSize = maxStackSize; this.localTypes = localTypes; @@ -63,6 +64,7 @@ public CodeEntry(int functionIndex, int maxStackSize, byte[] localTypes, byte[] this.callNodes = callNodes; this.bytecodeStartOffset = startOffset; this.bytecodeEndOffset = endOffset; + this.usesMemoryZero = usesMemoryZero; } public int maxStackSize() { @@ -92,4 +94,8 @@ public int bytecodeStartOffset() { public int bytecodeEndOffset() { return bytecodeEndOffset; } + + public boolean usesMemoryZero() { + return usesMemoryZero; + } } diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/parser/validation/ParserState.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/parser/validation/ParserState.java index 3dab12c42e2a..6c0b58559e8f 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/parser/validation/ParserState.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/parser/validation/ParserState.java @@ -65,6 +65,7 @@ public class ParserState { private final RuntimeBytecodeGen bytecode; private int maxStackSize; + private boolean usesMemoryZero; public ParserState(RuntimeBytecodeGen bytecode) { this.valueStack = new ByteArrayList(); @@ -76,7 +77,7 @@ public ParserState(RuntimeBytecodeGen bytecode) { /** * Pops a value from the stack if possible. Throws an error on stack underflow. - * + * * @param expectedValueType The expectedValueType used for error generation. * @return The top of the stack or -1. */ @@ -101,7 +102,7 @@ private byte popInternal(byte expectedValueType) { * are returned. If the number of values on the stack is greater or equal to the number of * expectedValueTypes, the values equal to the number of expectedValueTypes is popped from the * stack. - * + * * @param expectedValueTypes Value types expected on the stack. * @return The maximum of available stack values smaller than the length of expectedValueTypes. */ @@ -117,7 +118,7 @@ private byte[] popAvailableUnchecked(byte[] expectedValueTypes) { /** * Pops the maximum available values from the current stack frame. - * + * * @return The maximum of available stack values. */ private byte[] popAvailableUnchecked() { @@ -133,7 +134,7 @@ private byte[] popAvailableUnchecked() { /** * Checks if two sets of value types are equivalent. - * + * * @param expectedTypes The expected value types. * @param actualTypes The actual value types. * @return True if both are equivalent. @@ -155,7 +156,7 @@ private boolean isTypeMismatch(byte[] expectedTypes, byte[] actualTypes) { /** * Pushes a value type onto the stack. - * + * * @param valueType The value type that should be added. */ public void push(byte valueType) { @@ -165,7 +166,7 @@ public void push(byte valueType) { /** * Pushes all provided value types onto the stack. - * + * * @param valueTypes The value types that should be added. */ public void pushAll(byte[] valueTypes) { @@ -176,7 +177,7 @@ public void pushAll(byte[] valueTypes) { /** * Pops the topmost value type from the stack. Throws an error if the stack is empty. - * + * * @return The value type on top of the stack or -1. * @throws WasmException If the stack is empty. */ @@ -186,7 +187,7 @@ public byte pop() { /** * Pops the topmost value type from the stack and checks if it is equivalent to the given value. - * + * * @param expectedValueType The expected value type. * @return The value type on top of the stack. * @throws WasmException If the stack is empty or the value types do not match. @@ -220,7 +221,7 @@ public void popReferenceTypeChecked() { /** * Pops the topmost value types from the stack and checks if they are equivalent to the given * set of value types. - * + * * @param expectedValueTypes The expected value types. * @return The value types on top of the stack. * @throws WasmException If the stack is empty or the value types do not match. @@ -335,7 +336,7 @@ public void addConditionalBranch(int branchLabel) { /** * Performs the necessary branch checks and adds the unconditional branch information to the * extra data array. - * + * * @param branchLabel The target label. */ public void addUnconditionalBranch(int branchLabel) { @@ -349,7 +350,7 @@ public void addUnconditionalBranch(int branchLabel) { /** * Performs the necessary branch checks and adds the branch table information to the extra data * array. - * + * * @param branchLabels The target labels. */ public void addBranchTable(int[] branchLabels) { @@ -371,7 +372,7 @@ public void addBranchTable(int[] branchLabels) { /** * Performs the necessary checks for a function return. - * + * * @param multiValue If multiple return values are supported. */ public void addReturn(boolean multiValue) { @@ -386,7 +387,7 @@ public void addReturn(boolean multiValue) { /** * Adds the index of an indirect call node to the extra data array. - * + * * @param nodeIndex The index of the indirect call. */ public void addIndirectCall(int nodeIndex, int typeIndex, int tableIndex) { @@ -395,7 +396,7 @@ public void addIndirectCall(int nodeIndex, int typeIndex, int tableIndex) { /** * Adds the index of a direct call node to the extra data array. - * + * * @param nodeIndex The index of the direct call. */ public void addCall(int nodeIndex, int functionIndex) { @@ -425,7 +426,7 @@ public void addVectorFlag() { /** * Adds the given instruction and an i32 immediate value to the bytecode. - * + * * @param instruction The instruction * @param value The immediate value */ @@ -435,7 +436,7 @@ public void addInstruction(int instruction, int value) { /** * Adds the given instruction and an i64 immediate value to the bytecode. - * + * * @param instruction The instruction * @param value The immediate value */ @@ -455,7 +456,7 @@ public void addInstruction(int instruction, Vector128 value) { /** * Adds the given instruction and two i32 immediate values to the bytecode. - * + * * @param instruction The instruction * @param value1 The first immediate value * @param value2 The second immediate value @@ -468,7 +469,7 @@ public void addInstruction(int instruction, int value1, int value2) { * Adds the i8 or i32 version of the given instruction to the bytecode based on the given * immediate value. If the value fits into a signed i8 value, the i8 instruction and an i8 value * are added. Otherwise, the i32 instruction and an i32 value are added. - * + * * @param instruction The i8 version of the instruction * @param value The immediate value. */ @@ -480,7 +481,7 @@ public void addSignedInstruction(int instruction, int value) { * Adds the i8 or i64 version of the given instruction to the bytecode based on the given * immediate value. If the value fits into a signed i8 value, the i8 instruction and an i8 value * are added. Otherwise, the i64 instruction and i64 value are added. - * + * * @param instruction The i8 version of the instruction * @param value The immediate value */ @@ -492,7 +493,7 @@ public void addSignedInstruction(int instruction, long value) { * Adds the u8 or i32 version of the given instruction to the bytecode based on the given * immediate value. If the value fits into a u8 value, the u8 instruction and a u8 value are * added. Otherwise, the i32 instruction and an i32 value are added. - * + * * @param instruction The u8 version of the instruction * @param value The immediate value */ @@ -502,13 +503,14 @@ public void addUnsignedInstruction(int instruction, int value) { /** * Adds a memory instruction based on the given values and index type. - * + * * @param baseInstruction The base version of the memory instruction * @param memoryIndex The index of the memory being accessed * @param value The immediate value * @param indexType64 If the index type is 64 bit. */ public void addMemoryInstruction(int baseInstruction, int memoryIndex, long value, boolean indexType64) { + markMemoryUsed(memoryIndex); bytecode.addMemoryInstruction(baseInstruction, baseInstruction + 1, baseInstruction + 2, memoryIndex, value, indexType64); } @@ -522,6 +524,7 @@ public void addMemoryInstruction(int baseInstruction, int memoryIndex, long valu * @param indexType64 If the index type is 64 bit. */ public void addExtendedMemoryInstruction(int instruction, int memoryIndex, long value, boolean indexType64) { + markMemoryUsed(memoryIndex); bytecode.addExtendedMemoryInstruction(instruction, memoryIndex, value, indexType64); } @@ -535,13 +538,14 @@ public void addExtendedMemoryInstruction(int instruction, int memoryIndex, long * @param laneIndex The lane index */ public void addVectorMemoryLaneInstruction(int instruction, int memoryIndex, long value, boolean indexType64, byte laneIndex) { + markMemoryUsed(memoryIndex); bytecode.addExtendedMemoryInstruction(instruction, memoryIndex, value, indexType64); bytecode.add(laneIndex); } /** * Adds a lane-indexed vector instruction (extract_lane or replace_lane). - * + * * @param instruction The vector instruction * @param laneIndex The lane index */ @@ -554,7 +558,7 @@ public void addVectorLaneInstruction(int instruction, byte laneIndex) { * Finishes the current control frame and removes it from the control frame stack. * * @param multiValue If multiple return values are supported. - * + * * @throws WasmException If the number of return value types do not match with the remaining * stack or the number of return values is greater than 1. */ @@ -576,7 +580,7 @@ public void exit(boolean multiValue) { /** * Checks that the expected return types are actually on the value stack. - * + * * @param frame The frame that is exited. * @param resultTypes The expected return types of the frame. */ @@ -627,7 +631,7 @@ private void checkResultTypes(ControlFrame frame) { /** * Checks if the given parameter value types do match the current value types on the stack. - * + * * @param paramTypes The expected value types. * @throws WasmException If the parameter value types and the vale types on the stack do not * match. @@ -645,7 +649,7 @@ public void checkParamTypes(byte[] paramTypes) { /** * Checks if the given label is a valid jump target. - * + * * @param label The label which to jump to. * @throws WasmException If the label is out or reach. */ @@ -657,7 +661,7 @@ public void checkLabelExists(int label) { /** * Checks if the value types of two different labels match. - * + * * @param expectedTypes The expected value types. * @param actualTypes The value types that should be checked. * @throws WasmException If the provided sets of value types do not match. @@ -670,7 +674,7 @@ public void checkLabelTypes(byte[] expectedTypes, byte[] actualTypes) { /** * Checks if the given function type is within range. - * + * * @param typeIndex The function type. * @param max The number of available function types. * @throws WasmException If the given function type is greater or equal to the given maximum. @@ -701,4 +705,14 @@ public int valueStackSize() { public int maxStackSize() { return maxStackSize; } + + private void markMemoryUsed(int memoryIndex) { + if (memoryIndex == 0) { + usesMemoryZero = true; + } + } + + public boolean usesMemoryZero() { + return usesMemoryZero; + } }