Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions ci/common.jsonnet
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,24 @@ local common_json = import "../common.json";
},
},

wasm_ol8:: {
downloads+: {
WABT_DIR: {name: 'wabt', version: '1.0.36-ol8', platformspecific: true},
},
environment+: {
WABT_DIR: '$WABT_DIR/bin',
},
},

emsdk_ol8:: {
downloads+: {
EMSDK_DIR: {name: 'emsdk', version: '4.0.10', platformspecific: true},
},
environment+: {
EMCC_DIR: '$EMSDK_DIR/upstream/emscripten/'
}
},

fastr:: {
# Note: On both Linux and MacOS, FastR depends on the gnur module and on gfortran
# of a specific version (4.8.5 on Linux, 10.2.0 on MacOS)
Expand Down
10 changes: 5 additions & 5 deletions wasm/ci/ci.jsonnet
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,13 @@ jdks + wasm_common +
$.jdkLatest + platform + $.tier3 + $.gate_graalwasm_full + {environment+: {GATE_TAGS: 'build,wasmtest'}} + {name: 'gate-graalwasm-unittest' + self.name_suffix}
for platform in [$.linux_aarch64, $.windows_amd64, $.darwin_aarch64]
] + [
$.jdkLatest + $.linux_amd64 + $.tier2 + $.gate_graalwasm_emsdk_full + {environment+: {GATE_TAGS: 'buildall,wasmextratest'}} + {name: 'gate-graalwasm-extra-unittest' + self.name_suffix},
$.jdkLatest + $.linux_amd64 + $.tier2 + $.gate_graalwasm_emsdk_full + {environment+: {GATE_TAGS: 'buildall,wasmbenchtest'}} + {name: 'gate-graalwasm-benchtest' + self.name_suffix},
$.jdkLatest + $.linux_amd64_ol8 + $.tier2 + $.gate_graalwasm_emsdk_full + {environment+: {GATE_TAGS: 'buildall,wasmextratest'}} + {name: 'gate-graalwasm-extra-unittest' + self.name_suffix},
$.jdkLatest + $.linux_amd64_ol8 + $.tier2 + $.gate_graalwasm_emsdk_full + {environment+: {GATE_TAGS: 'buildall,wasmbenchtest'}} + {name: 'gate-graalwasm-benchtest' + self.name_suffix},

$.jdkLatest + $.linux_amd64 + $.weekly + $.gate_graalwasm_coverage + tools_java_home + {name: 'weekly-graalwasm-coverage' + self.name_suffix},
$.jdkLatest + $.linux_amd64_ol8 + $.weekly + $.gate_graalwasm_coverage + tools_java_home + {name: 'weekly-graalwasm-coverage' + self.name_suffix},

# Benchmark jobs.
$.jdkLatest + $.linux_amd64 + $.bench_daily + $.bench_graalwasm_emsdk_full + {
$.jdkLatest + $.linux_amd64_ol8 + $.bench_daily + $.bench_graalwasm_emsdk_full + {
name: 'bench-graalwasm-c-micro' + self.name_suffix,
environment+: {
BENCH_RUNNER: 'run-c-micro-benchmarks',
Expand All @@ -43,7 +43,7 @@ jdks + wasm_common +
},
},

$.jdkLatest + $.linux_amd64 + $.bench_daily + $.bench_graalwasm_emsdk_full + {
$.jdkLatest + $.linux_amd64_ol8 + $.bench_daily + $.bench_graalwasm_emsdk_full + {
name: 'bench-graalwasm-wat-micro' + self.name_suffix,
environment+: {
BENCH_RUNNER: 'run-wat-micro-benchmarks',
Expand Down
14 changes: 3 additions & 11 deletions wasm/ci/ci_common/common.jsonnet
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ local graal_suite_root = root_ci.graal_suite_root;
},

linux_amd64:: common.linux_amd64 + self.linux_common,
linux_amd64_ol8:: common.linux_amd64_ol8 + self.linux_common,
linux_aarch64:: common.linux_aarch64 + self.linux_common,

darwin_aarch64:: common.darwin_aarch64,
Expand All @@ -78,15 +79,6 @@ local graal_suite_root = root_ci.graal_suite_root;

windows_amd64:: common.windows_amd64 + self.windows_common,

emsdk:: {
downloads+: {
EMSDK_DIR: {name: 'emsdk', version: '1.39.13', platformspecific: true},
},
environment+: {
EMCC_DIR: '$EMSDK_DIR/emscripten/master/'
}
},

ocaml_dune:: {
downloads+: {
OCAML_DIR: {name: 'ocaml-dune', version: '3.16.1', platformspecific: true},
Expand Down Expand Up @@ -193,7 +185,7 @@ local graal_suite_root = root_ci.graal_suite_root;
},

eclipse_jdt :: common.deps.pylint + common.deps.eclipse + common.deps.jdt,
wabt_emsdk :: common.deps.wasm + self.emsdk,
wabt_emsdk_ocamlbuild :: common.deps.wasm + self.emsdk + self.ocaml_dune,
wabt_emsdk :: common.deps.wasm_ol8 + common.deps.emsdk_ol8,
wabt_emsdk_ocamlbuild :: common.deps.wasm_ol8 + common.deps.emsdk_ol8 + self.ocaml_dune,

}
4 changes: 2 additions & 2 deletions wasm/docs/contributor/TestsAndBenchmarks.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ To compile these programs, you will need to install additional dependencies on y
To build these additional tests and benchmarks, you need to:

1. Install the [Emscripten SDK](https://emscripten.org/docs/getting_started/downloads.html).
We currently test against Emscripten **1.39.13**.
We currently test against Emscripten **4.0.10**.
```bash
$ cd [preferred emsdk install location]

Expand Down Expand Up @@ -129,7 +129,7 @@ The benchmarks are kept in the `src/com.oracle.truffle.wasm.benchcases` MX proje
For the benchmarks to run, `NODE_DIR` has to be set. You can use the node version that is part of Emscripten, for example:

```bash
$ export NODE_DIR=[path to emsdk]/node/14.15.5_64bit/bin
$ export NODE_DIR=[path to emsdk]/node/22.16.0_64bit/bin
```

After building the additional benchmarks, as described in the last section, they can be executed as follows:
Expand Down
47 changes: 35 additions & 12 deletions wasm/mx.wasm/mx_wasm.py
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,6 @@ def processDeps(self, deps):
"_benchmarkSetupEach",
"_benchmarkTeardownEach",
"_benchmarkRun",
"_main"
]


Expand Down Expand Up @@ -446,6 +445,17 @@ def __str__(self):
def benchmark_methods(self):
return benchmark_methods

def test_methods(self, opts_path):
if not os.path.isfile(opts_path):
return []
with open(opts_path) as opts_file:
for line in opts_file:
line = line.strip()
if line.startswith("entry-point"):
_, value = line.split("=", 1)
return ['_' + value.strip()]
return []

def build(self):
source_dir = self.subject.getSourceDir()
output_dir = self.subject.getOutputDir()
Expand All @@ -469,9 +479,7 @@ def build(self):
include_flags = []
if hasattr(self.project, "includeset"):
include_flags = ["-I", os.path.join(_suite.dir, "includes", self.project.includeset)]
emcc_flags = ["-s", "EXIT_RUNTIME=1", "-s", "STANDALONE_WASM", "-s", "WASM_BIGINT"] + cc_flags
if self.project.isBenchmarkProject():
emcc_flags = emcc_flags + ["-s", "EXPORTED_FUNCTIONS=" + str(self.benchmark_methods()).replace("'", "\"") + ""]
emcc_flags = ["-s", "STANDALONE_WASM", "-s", "WASM_BIGINT"] + cc_flags
subdir_program_names = defaultdict(lambda: [])
for root, filename in self.subject.getProgramSources():
if filename.startswith("_"):
Expand All @@ -489,12 +497,27 @@ def build(self):
timestampedOutput = mx.TimeStampFile(output_wasm_path)
mustRebuild = timestampedSource.isNewerThan(timestampedOutput) or not timestampedOutput.exists()

source_cc_flags = []
native_bench = True
if filename.endswith(".c"):
with open(source_path) as f:
source_file = f.read()
for flags in re.findall(r'//\s*CFLAGS\s*=\s*(.*)\n', source_file):
source_cc_flags.extend(flags.split())
native_bench_option = re.search(r'//\s*NATIVE_BENCH\s*=\s*(.*)\n', source_file)
if native_bench_option:
native_bench = native_bench_option.group(1).lower() == "true"

# Step 1: build the .wasm binary.
if mustRebuild:
if filename.endswith(".c"):
if self.project.isBenchmarkProject():
emcc_export_flags = ["-s", "EXPORTED_FUNCTIONS=" + str(self.benchmark_methods()).replace("'", "\"") + ""]
else:
emcc_export_flags = ["-s", "EXPORTED_FUNCTIONS=" + str(self.test_methods(os.path.join(root, basename + ".opts"))).replace("'", "\"") + ""]
# This generates both a js file and a wasm file.
# See https://github.com/emscripten-core/emscripten/wiki/WebAssembly-Standalone
build_cmd_line = [emcc_cmd] + emcc_flags + [source_path, "-o", output_js_path] + include_flags
build_cmd_line = [emcc_cmd] + emcc_flags + emcc_export_flags + source_cc_flags + [source_path, "-o", output_js_path] + include_flags
if mx.run(build_cmd_line, nonZeroIsFatal=False) != 0:
mx.abort("Could not build the wasm-only output of " + filename + " with emcc.")
elif filename.endswith(".wat"):
Expand Down Expand Up @@ -533,11 +556,11 @@ def build(self):

# Step 5: if this is a benchmark project, create native binaries too.
if mustRebuild:
if filename.endswith(".c"):
if filename.endswith(".c") and native_bench:
mx_util.ensure_dir_exists(os.path.join(output_dir, subdir, NATIVE_BENCH_DIR))
output_path = os.path.join(output_dir, subdir, NATIVE_BENCH_DIR, mx.exe_suffix(basename))
link_flags = ["-lm"]
gcc_cmd_line = [gcc_cmd] + cc_flags + [source_path, "-o", output_path] + include_flags + link_flags
gcc_cmd_line = [gcc_cmd] + cc_flags + source_cc_flags + [source_path, "-o", output_path] + include_flags + link_flags
if mx.run(gcc_cmd_line, nonZeroIsFatal=False) != 0:
mx.abort("Could not build the native binary of " + filename + ".")
os.chmod(output_path, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR)
Expand Down Expand Up @@ -642,10 +665,10 @@ def emscripten_init(args):
config_path = os.path.join(os.getcwd(), args.config_path)
emsdk_path = args.emsdk_path

llvm_root = os.path.join(emsdk_path, "llvm", "git", "build_master_64", "bin")
binaryen_root = os.path.join(emsdk_path, "binaryen", "master_64bit_binaryen")
emscripten_root = os.path.join(emsdk_path, "emscripten", "master")
node_js = os.path.join(emsdk_path, "node", "12.9.1_64bit", "bin", "node")
llvm_root = os.path.join(emsdk_path, "upstream", "bin")
binaryen_root = os.path.join(emsdk_path, "binaryen", "main_64bit_binaryen")
emscripten_root = os.path.join(emsdk_path, "upstream", "emscripten")
node_js = os.path.join(emsdk_path, "node", "22.16.0_64bit", "bin", "node")

def find_executable(exe_name):
for root, _, files in os.walk(args.emsdk_path):
Expand All @@ -666,7 +689,7 @@ def find_executable(exe_name):
llvm_root = os.path.join(emsdk_path, "upstream", "bin")
binaryen_root = os.path.join(emsdk_path, "upstream", "lib")
emscripten_root = os.path.join(emsdk_path, "upstream", "emscripten")
node_js = os.path.join(emsdk_path, "node", "14.15.5_64bit", "bin", "node")
node_js = os.path.join(emsdk_path, "node", "22.16.0_64bit", "bin", "node")

mx.log("Generating Emscripten configuration...")
mx.log("Config file path: " + str(config_path))
Expand Down
2 changes: 1 addition & 1 deletion wasm/mx.wasm/mx_wasm_benchmark.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ def run_vm(self, args, out=None, err=None, cwd=None, nonZeroIsFatal=False):
try:
tmp_dir = self.extract_jar_to_tempdir(jar, suite, benchmark)
node_cmd = os.path.join(node_dir, "node")
node_cmd_line = [node_cmd, "--experimental-wasm-bigint", os.path.join(tmp_dir, "bench", suite, benchmark + ".js")]
node_cmd_line = [node_cmd, os.path.join(tmp_dir, "bench", suite, benchmark + ".js")]
mx.log("Running benchmark " + benchmark + " with node.")
mx.run(node_cmd_line, cwd=tmp_dir, out=out, err=err, nonZeroIsFatal=nonZeroIsFatal)
finally:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -216,9 +216,21 @@ private void runInContext(WasmCase testCase, Context context, List<Source> sourc
}

final WasmContext wasmContext = WasmContext.get(null);
final Value mainFunction = findMain(moduleInstances);
final List<WasmInstance> instanceList = moduleInstances.stream().map(i -> toWasmInstance(i)).toList();

final Value testFunction;
final String entryPoint = testCase.options().getProperty("entry-point");
if (entryPoint != null) {
String testModuleName = testCase.name();
Value testModule = context.getBindings(WasmLanguage.ID).getMember(testModuleName).getMember("exports");
testFunction = testModule.getMember(entryPoint);
if (testFunction == null) {
throw new RuntimeException(String.format("Entry point %s not found in test module %s.", entryPoint, testCase.name()));
}
} else {
testFunction = findMain(moduleInstances);
}

resetStatus(System.out, phaseIcon, phaseLabel);

final String argString = testCase.options().getProperty("argument");
Expand All @@ -228,7 +240,7 @@ private void runInContext(WasmCase testCase, Context context, List<Source> sourc
for (int i = 0; i != iterations; ++i) {
try {
testOut.reset();
final Value result = arg == null ? mainFunction.execute() : mainFunction.execute(arg);
final Value result = arg == null ? testFunction.execute() : testFunction.execute(arg);
WasmCase.validateResult(testCase.data().resultValidator(), result, testOut);
} catch (PolyglotException e) {
// If no exception is expected and the program returns with success exit status,
Expand Down Expand Up @@ -341,6 +353,7 @@ private WasmTestStatus runTestCase(WasmCase testCase, Engine sharedEngine) {

contextBuilder.option("wasm.Builtins", includedExternalModules());
contextBuilder.option("wasm.WasiConstantRandomGet", "true");
contextBuilder.option("wasm.EvalReturnsInstance", "true");
final String commandLineArgs = testCase.options().getProperty("command-line-args");
if (commandLineArgs != null) {
// The first argument is the program name. We set it to the empty string in tests.
Expand Down Expand Up @@ -415,7 +428,7 @@ private void runInContexts(WasmCase testCase, Context.Builder contextBuilder, Ar
interpreterIterations = Math.min(interpreterIterations, 1);
}

context = contextBuilder.options(getInterpreted()).option("wasm.EvalReturnsInstance", "true").build();
context = contextBuilder.options(getInterpreted()).build();
runInContext(testCase, context, sources, interpreterIterations, PHASE_INTERPRETER_ICON, "interpreter", testOut);

if (isFallbackRuntime()) {
Expand All @@ -429,7 +442,7 @@ private void runInContexts(WasmCase testCase, Context.Builder contextBuilder, Ar
if (WasmTestOptions.COVERAGE_MODE) {
syncNoinlineIterations = Math.min(syncNoinlineIterations, 1);
}
context = contextBuilder.options(getSyncCompiledNoInline()).option("wasm.EvalReturnsInstance", "true").build();
context = contextBuilder.options(getSyncCompiledNoInline()).build();
runInContext(testCase, context, sources, syncNoinlineIterations, PHASE_SYNC_NO_INLINE_ICON, "sync,no-inl", testOut);

// Run in synchronous compiled mode, with inlining turned on.
Expand All @@ -439,15 +452,15 @@ private void runInContexts(WasmCase testCase, Context.Builder contextBuilder, Ar
if (WasmTestOptions.COVERAGE_MODE) {
syncInlineIterations = Math.min(syncInlineIterations, 1);
}
context = contextBuilder.options(getSyncCompiledWithInline()).option("wasm.EvalReturnsInstance", "true").build();
context = contextBuilder.options(getSyncCompiledWithInline()).build();
runInContext(testCase, context, sources, syncInlineIterations, PHASE_SYNC_INLINE_ICON, "sync,inl", testOut);

// Run with normal, asynchronous compilation.
int asyncIterations = Integer.parseInt(testCase.options().getProperty("async-iterations", String.valueOf(DEFAULT_ASYNC_ITERATIONS)));
if (WasmTestOptions.COVERAGE_MODE) {
asyncIterations = Math.min(asyncIterations, 1);
}
context = contextBuilder.options(getAsyncCompiled()).option("wasm.EvalReturnsInstance", "true").build();
context = contextBuilder.options(getAsyncCompiled()).build();
runInContext(testCase, context, sources, asyncIterations, PHASE_ASYNC_ICON, "async,multi", testOut);
} else {
int asyncSharedIterations = testCase.options().containsKey("async-iterations") && !testCase.options().containsKey("async-shared-iterations")
Expand All @@ -456,7 +469,7 @@ private void runInContexts(WasmCase testCase, Context.Builder contextBuilder, Ar
if (WasmTestOptions.COVERAGE_MODE) {
asyncSharedIterations = Math.min(asyncSharedIterations, 1);
}
context = contextBuilder.option("wasm.EvalReturnsInstance", "true").build();
context = contextBuilder.build();
runInContext(testCase, context, sources, asyncSharedIterations, PHASE_SHARED_ENGINE_ICON, "async,shared", testOut);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
#include <stdlib.h>
#include <string.h>

int main() {
int test() {
char staticMemory[100];
char *dynamicMemory;

Expand All @@ -59,3 +59,7 @@ int main() {
printf("2nd: %s\n", dynamicMemory);
return 0;
}

int main() {
return test();
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ interpreter-iterations = 2
sync-noinline-iterations = 0
sync-inline-iterations = 0
async-iterations = 2000
entry-point = test
5 changes: 4 additions & 1 deletion wasm/src/org.graalvm.wasm.testcases/src/test/c/collatz.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,11 @@ int collatz(int n) {

int number = 127;

int main() {
int test() {
printf("%d\n", collatz(number));
return 0;
}

int main() {
return test();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
entry-point = test
6 changes: 5 additions & 1 deletion wasm/src/org.graalvm.wasm.testcases/src/test/c/floyd.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@

#include <stdio.h>

int main() {
int test() {
int number = 1;
int rows = 10;
for (int i = 1; i <= rows; i++) {
Expand All @@ -53,3 +53,7 @@ int main() {
}
return 0;
}

int main() {
return test();
}
1 change: 1 addition & 0 deletions wasm/src/org.graalvm.wasm.testcases/src/test/c/floyd.opts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ interpreter-iterations = 4
sync-noinline-iterations = 0
sync-inline-iterations = 0
async-iterations = 500
entry-point = test
5 changes: 4 additions & 1 deletion wasm/src/org.graalvm.wasm.testcases/src/test/c/hello.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,11 @@
*/
#include <stdio.h>

int main() {
int test() {
printf("Hello world!\n");
return 0;
}

int main() {
return test();
}
1 change: 1 addition & 0 deletions wasm/src/org.graalvm.wasm.testcases/src/test/c/hello.opts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ interpreter-iterations = 3
sync-noinline-iterations = 2
sync-inline-iterations = 2
async-iterations = 1250
entry-point = test